Added tests for Task.WhenAll w/ empty list
[mono.git] / mcs / mcs / doc.cs
1 //
2 // doc.cs: Support for XML documentation comment.
3 //
4 // Authors:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //  Marek Safar (marek.safar@gmail.com>
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2004 Novell, Inc.
11 // Copyright 2011 Xamarin Inc
12 //
13 //
14
15 using System;
16 using System.Collections.Generic;
17 using System.IO;
18 using System.Text;
19 using System.Xml;
20 using System.Linq;
21
22 namespace Mono.CSharp
23 {
24         //
25         // Implements XML documentation generation.
26         //
27         class DocumentationBuilder
28         {
29                 //
30                 // Used to create element which helps well-formedness checking.
31                 //
32                 readonly XmlDocument XmlDocumentation;
33
34                 readonly ModuleContainer module;
35                 readonly ModuleContainer doc_module;
36
37                 //
38                 // The output for XML documentation.
39                 //
40                 XmlWriter XmlCommentOutput;
41
42                 static readonly string line_head = Environment.NewLine + "            ";
43
44                 //
45                 // Stores XmlDocuments that are included in XML documentation.
46                 // Keys are included filenames, values are XmlDocuments.
47                 //
48                 Dictionary<string, XmlDocument> StoredDocuments = new Dictionary<string, XmlDocument> ();
49
50                 ParserSession session;
51
52                 public DocumentationBuilder (ModuleContainer module)
53                 {
54                         doc_module = new ModuleContainer (module.Compiler);
55                         doc_module.DocumentationBuilder = this;
56
57                         this.module = module;
58                         XmlDocumentation = new XmlDocument ();
59                         XmlDocumentation.PreserveWhitespace = false;
60                 }
61
62                 Report Report {
63                         get {
64                                 return module.Compiler.Report;
65                         }
66                 }
67
68                 public MemberName ParsedName {
69                         get; set;
70                 }
71
72                 public List<DocumentationParameter> ParsedParameters {
73                         get; set;
74                 }
75
76                 public TypeExpression ParsedBuiltinType {
77                         get; set;
78                 }
79
80                 public Operator.OpType? ParsedOperator {
81                         get; set;
82                 }
83
84                 XmlNode GetDocCommentNode (MemberCore mc, string name)
85                 {
86                         // FIXME: It could be even optimizable as not
87                         // to use XmlDocument. But anyways the nodes
88                         // are not kept in memory.
89                         XmlDocument doc = XmlDocumentation;
90                         try {
91                                 XmlElement el = doc.CreateElement ("member");
92                                 el.SetAttribute ("name", name);
93                                 string normalized = mc.DocComment;
94                                 el.InnerXml = normalized;
95                                 // csc keeps lines as written in the sources
96                                 // and inserts formatting indentation (which 
97                                 // is different from XmlTextWriter.Formatting
98                                 // one), but when a start tag contains an 
99                                 // endline, it joins the next line. We don't
100                                 // have to follow such a hacky behavior.
101                                 string [] split =
102                                         normalized.Split ('\n');
103                                 int j = 0;
104                                 for (int i = 0; i < split.Length; i++) {
105                                         string s = split [i].TrimEnd ();
106                                         if (s.Length > 0)
107                                                 split [j++] = s;
108                                 }
109                                 el.InnerXml = line_head + String.Join (
110                                         line_head, split, 0, j);
111                                 return el;
112                         } catch (Exception ex) {
113                                 Report.Warning (1570, 1, mc.Location, "XML documentation comment on `{0}' is not well-formed XML markup ({1})",
114                                         mc.GetSignatureForError (), ex.Message);
115
116                                 return doc.CreateComment (String.Format ("FIXME: Invalid documentation markup was found for member {0}", name));
117                         }
118                 }
119
120                 //
121                 // Generates xml doc comments (if any), and if required,
122                 // handle warning report.
123                 //
124                 internal void GenerateDocumentationForMember (MemberCore mc)
125                 {
126                         string name = mc.DocCommentHeader + mc.GetSignatureForDocumentation ();
127
128                         XmlNode n = GetDocCommentNode (mc, name);
129
130                         XmlElement el = n as XmlElement;
131                         if (el != null) {
132                                 var pm = mc as IParametersMember;
133                                 if (pm != null) {
134                                         CheckParametersComments (mc, pm, el);
135                                 }
136
137                                 // FIXME: it could be done with XmlReader
138                                 XmlNodeList nl = n.SelectNodes (".//include");
139                                 if (nl.Count > 0) {
140                                         // It could result in current node removal, so prepare another list to iterate.
141                                         var al = new List<XmlNode> (nl.Count);
142                                         foreach (XmlNode inc in nl)
143                                                 al.Add (inc);
144                                         foreach (XmlElement inc in al)
145                                                 if (!HandleInclude (mc, inc))
146                                                         inc.ParentNode.RemoveChild (inc);
147                                 }
148
149                                 // FIXME: it could be done with XmlReader
150                                 var ds_target = mc as TypeContainer;
151                                 if (ds_target == null)
152                                         ds_target = mc.Parent;
153
154                                 foreach (XmlElement see in n.SelectNodes (".//see"))
155                                         HandleSee (mc, ds_target, see);
156                                 foreach (XmlElement seealso in n.SelectNodes (".//seealso"))
157                                         HandleSeeAlso (mc, ds_target, seealso);
158                                 foreach (XmlElement see in n.SelectNodes (".//exception"))
159                                         HandleException (mc, ds_target, see);
160                                 foreach (XmlElement node in n.SelectNodes (".//typeparam"))
161                                         HandleTypeParam (mc, node);
162                                 foreach (XmlElement node in n.SelectNodes (".//typeparamref"))
163                                         HandleTypeParamRef (mc, node);
164                         }
165
166                         n.WriteTo (XmlCommentOutput);
167                 }
168
169                 //
170                 // Processes "include" element. Check included file and
171                 // embed the document content inside this documentation node.
172                 //
173                 bool HandleInclude (MemberCore mc, XmlElement el)
174                 {
175                         bool keep_include_node = false;
176                         string file = el.GetAttribute ("file");
177                         string path = el.GetAttribute ("path");
178
179                         if (file == "") {
180                                 Report.Warning (1590, 1, mc.Location, "Invalid XML `include' element. Missing `file' attribute");
181                                 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Include tag is invalid "), el);
182                                 keep_include_node = true;
183                         } else if (path.Length == 0) {
184                                 Report.Warning (1590, 1, mc.Location, "Invalid XML `include' element. Missing `path' attribute");
185                                 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Include tag is invalid "), el);
186                                 keep_include_node = true;
187                         } else {
188                                 XmlDocument doc;
189                                 Exception exception = null;
190                                 var full_path = Path.Combine (Path.GetDirectoryName (mc.Location.NameFullPath), file);
191
192                                 if (!StoredDocuments.TryGetValue (full_path, out doc)) {
193                                         try {
194                                                 doc = new XmlDocument ();
195                                                 doc.Load (full_path);
196                                                 StoredDocuments.Add (full_path, doc);
197                                         } catch (Exception e) {
198                                                 exception = e;
199                                                 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (String.Format (" Badly formed XML in at comment file `{0}': cannot be included ", file)), el);
200                                         }
201                                 }
202
203                                 if (doc != null) {
204                                         try {
205                                                 XmlNodeList nl = doc.SelectNodes (path);
206                                                 if (nl.Count == 0) {
207                                                         el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" No matching elements were found for the include tag embedded here. "), el);
208                                         
209                                                         keep_include_node = true;
210                                                 }
211                                                 foreach (XmlNode n in nl)
212                                                         el.ParentNode.InsertBefore (el.OwnerDocument.ImportNode (n, true), el);
213                                         } catch (Exception ex) {
214                                                 exception = ex;
215                                                 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Failed to insert some or all of included XML "), el);
216                                         }
217                                 }
218
219                                 if (exception != null) {
220                                         Report.Warning (1589, 1, mc.Location, "Unable to include XML fragment `{0}' of file `{1}'. {2}",
221                                                 path, file, exception.Message);
222                                 }
223                         }
224
225                         return keep_include_node;
226                 }
227
228                 //
229                 // Handles <see> elements.
230                 //
231                 void HandleSee (MemberCore mc, TypeContainer ds, XmlElement see)
232                 {
233                         HandleXrefCommon (mc, ds, see);
234                 }
235
236                 //
237                 // Handles <seealso> elements.
238                 //
239                 void HandleSeeAlso (MemberCore mc, TypeContainer ds, XmlElement seealso)
240                 {
241                         HandleXrefCommon (mc, ds, seealso);
242                 }
243
244                 //
245                 // Handles <exception> elements.
246                 //
247                 void HandleException (MemberCore mc, TypeContainer ds, XmlElement seealso)
248                 {
249                         HandleXrefCommon (mc, ds, seealso);
250                 }
251
252                 //
253                 // Handles <typeparam /> node
254                 //
255                 static void HandleTypeParam (MemberCore mc, XmlElement node)
256                 {
257                         if (!node.HasAttribute ("name"))
258                                 return;
259
260                         string tp_name = node.GetAttribute ("name");
261                         if (mc.CurrentTypeParameters != null) {
262                                 if (mc.CurrentTypeParameters.Find (tp_name) != null)
263                                         return;
264                         }
265                         
266                         // TODO: CS1710, CS1712
267                         
268                         mc.Compiler.Report.Warning (1711, 2, mc.Location,
269                                 "XML comment on `{0}' has a typeparam name `{1}' but there is no type parameter by that name",
270                                 mc.GetSignatureForError (), tp_name);
271                 }
272
273                 //
274                 // Handles <typeparamref /> node
275                 //
276                 static void HandleTypeParamRef (MemberCore mc, XmlElement node)
277                 {
278                         if (!node.HasAttribute ("name"))
279                                 return;
280
281                         string tp_name = node.GetAttribute ("name");
282                         var member = mc;
283                         do {
284                                 if (member.CurrentTypeParameters != null) {
285                                         if (member.CurrentTypeParameters.Find (tp_name) != null)
286                                                 return;
287                                 }
288
289                                 member = member.Parent;
290                         } while (member != null);
291
292                         mc.Compiler.Report.Warning (1735, 2, mc.Location,
293                                 "XML comment on `{0}' has a typeparamref name `{1}' that could not be resolved",
294                                 mc.GetSignatureForError (), tp_name);
295                 }
296
297                 FullNamedExpression ResolveMemberName (IMemberContext context, MemberName mn)
298                 {
299                         if (mn.Left == null)
300                                 return context.LookupNamespaceOrType (mn.Name, mn.Arity, LookupMode.Probing, Location.Null);
301
302                         var left = ResolveMemberName (context, mn.Left);
303                         var ns = left as Namespace;
304                         if (ns != null)
305                                 return ns.LookupTypeOrNamespace (context, mn.Name, mn.Arity, LookupMode.Probing, Location.Null);
306
307                         TypeExpr texpr = left as TypeExpr;
308                         if (texpr != null) {
309                                 var found = MemberCache.FindNestedType (texpr.Type, ParsedName.Name, ParsedName.Arity);
310                                 if (found != null)
311                                         return new TypeExpression (found, Location.Null);
312
313                                 return null;
314                         }
315
316                         return left;
317                 }
318
319                 //
320                 // Processes "see" or "seealso" elements from cref attribute.
321                 //
322                 void HandleXrefCommon (MemberCore mc, TypeContainer ds, XmlElement xref)
323                 {
324                         string cref = xref.GetAttribute ("cref");
325                         // when, XmlReader, "if (cref == null)"
326                         if (!xref.HasAttribute ("cref"))
327                                 return;
328
329                         // Nothing to be resolved the reference is marked explicitly
330                         if (cref.Length > 2 && cref [1] == ':')
331                                 return;
332
333                         // Additional symbols for < and > are allowed for easier XML typing
334                         cref = cref.Replace ('{', '<').Replace ('}', '>');
335
336                         var encoding = module.Compiler.Settings.Encoding;
337                         var s = new MemoryStream (encoding.GetBytes (cref));
338
339                         var source_file = new CompilationSourceFile (doc_module, mc.Location.SourceFile);
340                         var report = new Report (doc_module.Compiler, new NullReportPrinter ());
341
342                         if (session == null)
343                                 session = new ParserSession () {
344                                         UseJayGlobalArrays = true
345                                 };
346
347                         SeekableStreamReader seekable = new SeekableStreamReader (s, encoding, session.StreamReaderBuffer);
348
349                         var parser = new CSharpParser (seekable, source_file, report, session);
350                         ParsedParameters = null;
351                         ParsedName = null;
352                         ParsedBuiltinType = null;
353                         ParsedOperator = null;
354                         parser.Lexer.putback_char = Tokenizer.DocumentationXref;
355                         parser.Lexer.parsing_generic_declaration_doc = true;
356                         parser.parse ();
357                         if (report.Errors > 0) {
358                                 Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
359                                         mc.GetSignatureForError (), cref);
360
361                                 xref.SetAttribute ("cref", "!:" + cref);
362                                 return;
363                         }
364
365                         MemberSpec member;
366                         string prefix = null;
367                         FullNamedExpression fne = null;
368
369                         //
370                         // Try built-in type first because we are using ParsedName as identifier of
371                         // member names on built-in types
372                         //
373                         if (ParsedBuiltinType != null && (ParsedParameters == null || ParsedName != null)) {
374                                 member = ParsedBuiltinType.Type;
375                         } else {
376                                 member = null;
377                         }
378
379                         if (ParsedName != null || ParsedOperator.HasValue) {
380                                 TypeSpec type = null;
381                                 string member_name = null;
382
383                                 if (member == null) {
384                                         if (ParsedOperator.HasValue) {
385                                                 type = mc.CurrentType;
386                                         } else if (ParsedName.Left != null) {
387                                                 fne = ResolveMemberName (mc, ParsedName.Left);
388                                                 if (fne != null) {
389                                                         var ns = fne as Namespace;
390                                                         if (ns != null) {
391                                                                 fne = ns.LookupTypeOrNamespace (mc, ParsedName.Name, ParsedName.Arity, LookupMode.Probing, Location.Null);
392                                                                 if (fne != null) {
393                                                                         member = fne.Type;
394                                                                 }
395                                                         } else {
396                                                                 type = fne.Type;
397                                                         }
398                                                 }
399                                         } else {
400                                                 fne = ResolveMemberName (mc, ParsedName);
401                                                 if (fne == null) {
402                                                         type = mc.CurrentType;
403                                                 } else if (ParsedParameters == null) {
404                                                         member = fne.Type;
405                                                 } else if (fne.Type.MemberDefinition == mc.CurrentType.MemberDefinition) {
406                                                         member_name = Constructor.ConstructorName;
407                                                         type = fne.Type;
408                                                 }
409                                         }
410                                 } else {
411                                         type = (TypeSpec) member;
412                                         member = null;
413                                 }
414
415                                 if (ParsedParameters != null) {
416                                         var old_printer = mc.Module.Compiler.Report.SetPrinter (new NullReportPrinter ());
417                                         try {
418                                                 var context = new DocumentationMemberContext (mc, ParsedName ?? MemberName.Null);
419
420                                                 foreach (var pp in ParsedParameters) {
421                                                         pp.Resolve (context);
422                                                 }
423                                         } finally {
424                                                 mc.Module.Compiler.Report.SetPrinter (old_printer);
425                                         }
426                                 }
427
428                                 if (type != null) {
429                                         if (member_name == null)
430                                                 member_name = ParsedOperator.HasValue ?
431                                                         Operator.GetMetadataName (ParsedOperator.Value) : ParsedName.Name;
432
433                                         int parsed_param_count;
434                                         if (ParsedOperator == Operator.OpType.Explicit || ParsedOperator == Operator.OpType.Implicit) {
435                                                 parsed_param_count = ParsedParameters.Count - 1;
436                                         } else if (ParsedParameters != null) {
437                                                 parsed_param_count = ParsedParameters.Count;
438                                         } else {
439                                                 parsed_param_count = 0;
440                                         }
441
442                                         int parameters_match = -1;
443                                         do {
444                                                 var members = MemberCache.FindMembers (type, member_name, true);
445                                                 if (members != null) {
446                                                         foreach (var m in members) {
447                                                                 if (ParsedName != null && m.Arity != ParsedName.Arity)
448                                                                         continue;
449
450                                                                 if (ParsedParameters != null) {
451                                                                         IParametersMember pm = m as IParametersMember;
452                                                                         if (pm == null)
453                                                                                 continue;
454
455                                                                         if (m.Kind == MemberKind.Operator && !ParsedOperator.HasValue)
456                                                                                 continue;
457
458                                                                         var pm_params = pm.Parameters;
459
460                                                                         int i;
461                                                                         for (i = 0; i < parsed_param_count; ++i) {
462                                                                                 var pparam = ParsedParameters[i];
463
464                                                                                 if (i >= pm_params.Count || pparam == null || pparam.TypeSpec == null ||
465                                                                                         !TypeSpecComparer.Override.IsEqual (pparam.TypeSpec, pm_params.Types[i]) ||
466                                                                                         (pparam.Modifier & Parameter.Modifier.RefOutMask) != (pm_params.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) {
467
468                                                                                         if (i > parameters_match) {
469                                                                                                 parameters_match = i;
470                                                                                         }
471
472                                                                                         i = -1;
473                                                                                         break;
474                                                                                 }
475                                                                         }
476
477                                                                         if (i < 0)
478                                                                                 continue;
479
480                                                                         if (ParsedOperator == Operator.OpType.Explicit || ParsedOperator == Operator.OpType.Implicit) {
481                                                                                 if (pm.MemberType != ParsedParameters[parsed_param_count].TypeSpec) {
482                                                                                         parameters_match = parsed_param_count + 1;
483                                                                                         continue;
484                                                                                 }
485                                                                         } else {
486                                                                                 if (parsed_param_count != pm_params.Count)
487                                                                                         continue;
488                                                                         }
489                                                                 }
490
491                                                                 if (member != null) {
492                                                                         Report.Warning (419, 3, mc.Location,
493                                                                                 "Ambiguous reference in cref attribute `{0}'. Assuming `{1}' but other overloads including `{2}' have also matched",
494                                                                                 cref, member.GetSignatureForError (), m.GetSignatureForError ());
495
496                                                                         break;
497                                                                 }
498
499                                                                 member = m;
500                                                         }
501                                                 }
502
503                                                 // Continue with parent type for nested types
504                                                 if (member == null) {
505                                                         type = type.DeclaringType;
506                                                 } else {
507                                                         type = null;
508                                                 }
509                                         } while (type != null);
510
511                                         if (member == null && parameters_match >= 0) {
512                                                 for (int i = parameters_match; i < parsed_param_count; ++i) {
513                                                         Report.Warning (1580, 1, mc.Location, "Invalid type for parameter `{0}' in XML comment cref attribute `{1}'",
514                                                                         (i + 1).ToString (), cref);
515                                                 }
516
517                                                 if (parameters_match == parsed_param_count + 1) {
518                                                         Report.Warning (1581, 1, mc.Location, "Invalid return type in XML comment cref attribute `{0}'", cref);
519                                                 }
520                                         }
521                                 }
522                         }
523
524                         if (member == null) {
525                                 Report.Warning (1574, 1, mc.Location, "XML comment on `{0}' has cref attribute `{1}' that could not be resolved",
526                                         mc.GetSignatureForError (), cref);
527                                 cref = "!:" + cref;
528                         } else if (member == InternalType.Namespace) {
529                                 cref = "N:" + fne.GetSignatureForError ();
530                         } else {
531                                 prefix = GetMemberDocHead (member);
532                                 cref = prefix + member.GetSignatureForDocumentation ();
533                         }
534
535                         xref.SetAttribute ("cref", cref);
536                 }
537
538                 //
539                 // Get a prefix from member type for XML documentation (used
540                 // to formalize cref target name).
541                 //
542                 static string GetMemberDocHead (MemberSpec type)
543                 {
544                         if (type is FieldSpec)
545                                 return "F:";
546                         if (type is MethodSpec)
547                                 return "M:";
548                         if (type is EventSpec)
549                                 return "E:";
550                         if (type is PropertySpec)
551                                 return "P:";
552                         if (type is TypeSpec)
553                                 return "T:";
554
555                         throw new NotImplementedException (type.GetType ().ToString ());
556                 }
557
558                 //
559                 // Raised (and passed an XmlElement that contains the comment)
560                 // when GenerateDocComment is writing documentation expectedly.
561                 //
562                 // FIXME: with a few effort, it could be done with XmlReader,
563                 // that means removal of DOM use.
564                 //
565                 void CheckParametersComments (MemberCore member, IParametersMember paramMember, XmlElement el)
566                 {
567                         HashSet<string> found_tags = null;
568                         foreach (XmlElement pelem in el.SelectNodes ("param")) {
569                                 string xname = pelem.GetAttribute ("name");
570                                 if (xname.Length == 0)
571                                         continue; // really? but MS looks doing so
572
573                                 if (found_tags == null) {
574                                         found_tags = new HashSet<string> ();
575                                 }
576
577                                 if (xname != "" && paramMember.Parameters.GetParameterIndexByName (xname) < 0) {
578                                         Report.Warning (1572, 2, member.Location,
579                                                 "XML comment on `{0}' has a param tag for `{1}', but there is no parameter by that name",
580                                                 member.GetSignatureForError (), xname);
581                                         continue;
582                                 }
583
584                                 if (found_tags.Contains (xname)) {
585                                         Report.Warning (1571, 2, member.Location,
586                                                 "XML comment on `{0}' has a duplicate param tag for `{1}'",
587                                                 member.GetSignatureForError (), xname);
588                                         continue;
589                                 }
590
591                                 found_tags.Add (xname);
592                         }
593
594                         if (found_tags != null) {
595                                 foreach (Parameter p in paramMember.Parameters.FixedParameters) {
596                                         if (!found_tags.Contains (p.Name) && !(p is ArglistParameter))
597                                                 Report.Warning (1573, 4, member.Location,
598                                                         "Parameter `{0}' has no matching param tag in the XML comment for `{1}'",
599                                                         p.Name, member.GetSignatureForError ());
600                                 }
601                         }
602                 }
603
604                 //
605                 // Outputs XML documentation comment from tokenized comments.
606                 //
607                 public bool OutputDocComment (string asmfilename, string xmlFileName)
608                 {
609                         XmlTextWriter w = null;
610                         try {
611                                 w = new XmlTextWriter (xmlFileName, null);
612                                 w.Indentation = 4;
613                                 w.Formatting = Formatting.Indented;
614                                 w.WriteStartDocument ();
615                                 w.WriteStartElement ("doc");
616                                 w.WriteStartElement ("assembly");
617                                 w.WriteStartElement ("name");
618                                 w.WriteString (Path.GetFileNameWithoutExtension (asmfilename));
619                                 w.WriteEndElement (); // name
620                                 w.WriteEndElement (); // assembly
621                                 w.WriteStartElement ("members");
622                                 XmlCommentOutput = w;
623                                 module.GenerateDocComment (this);
624                                 w.WriteFullEndElement (); // members
625                                 w.WriteEndElement ();
626                                 w.WriteWhitespace (Environment.NewLine);
627                                 w.WriteEndDocument ();
628                                 return true;
629                         } catch (Exception ex) {
630                                 Report.Error (1569, "Error generating XML documentation file `{0}' (`{1}')", xmlFileName, ex.Message);
631                                 return false;
632                         } finally {
633                                 if (w != null)
634                                         w.Close ();
635                         }
636                 }
637         }
638
639         //
640         // Type lookup of documentation references uses context of type where
641         // the reference is used but type parameters from cref value
642         //
643         sealed class DocumentationMemberContext : IMemberContext
644         {
645                 readonly MemberCore host;
646                 MemberName contextName;
647
648                 public DocumentationMemberContext (MemberCore host, MemberName contextName)
649                 {
650                         this.host = host;
651                         this.contextName = contextName;
652                 }
653
654                 public TypeSpec CurrentType {
655                         get {
656                                 return host.CurrentType;
657                         }
658                 }
659
660                 public TypeParameters CurrentTypeParameters {
661                         get {
662                                 return contextName.TypeParameters;
663                         }
664                 }
665
666                 public MemberCore CurrentMemberDefinition {
667                         get {
668                                 return host.CurrentMemberDefinition;
669                         }
670                 }
671
672                 public bool IsObsolete {
673                         get {
674                                 return false;
675                         }
676                 }
677
678                 public bool IsUnsafe {
679                         get {
680                                 return host.IsStatic;
681                         }
682                 }
683
684                 public bool IsStatic {
685                         get {
686                                 return host.IsStatic;
687                         }
688                 }
689
690                 public ModuleContainer Module {
691                         get {
692                                 return host.Module;
693                         }
694                 }
695
696                 public string GetSignatureForError ()
697                 {
698                         return host.GetSignatureForError ();
699                 }
700
701                 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
702                 {
703                         return null;
704                 }
705
706                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
707                 {
708                         if (arity == 0) {
709                                 var tp = CurrentTypeParameters;
710                                 if (tp != null) {
711                                         for (int i = 0; i < tp.Count; ++i) {
712                                                 var t = tp[i];
713                                                 if (t.Name == name) {
714                                                         t.Type.DeclaredPosition = i;
715                                                         return new TypeParameterExpr (t, loc);
716                                                 }
717                                         }
718                                 }
719                         }
720
721                         return host.Parent.LookupNamespaceOrType (name, arity, mode, loc);
722                 }
723
724                 public FullNamedExpression LookupNamespaceAlias (string name)
725                 {
726                         throw new NotImplementedException ();
727                 }
728         }
729
730         class DocumentationParameter
731         {
732                 public readonly Parameter.Modifier Modifier;
733                 public FullNamedExpression Type;
734                 TypeSpec type;
735
736                 public DocumentationParameter (Parameter.Modifier modifier, FullNamedExpression type)
737                         : this (type)
738                 {
739                         this.Modifier = modifier;
740                 }
741
742                 public DocumentationParameter (FullNamedExpression type)
743                 {
744                         this.Type = type;
745                 }
746
747                 public TypeSpec TypeSpec {
748                         get {
749                                 return type;
750                         }
751                 }
752
753                 public void Resolve (IMemberContext context)
754                 {
755                         type = Type.ResolveAsType (context);
756                 }
757         }
758 }