~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

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