2 // doc.cs: Support for XML documentation comment.
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2004 Novell, Inc.
14 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Runtime.CompilerServices;
19 using System.Runtime.InteropServices;
20 using System.Security;
21 using System.Security.Permissions;
26 using Mono.CompilerServices.SymbolWriter;
28 namespace Mono.CSharp {
31 // Support class for XML documentation.
38 // Generates xml doc comments (if any), and if required,
39 // handle warning report.
41 internal static void GenerateTypeDocComment (TypeContainer t,
42 DeclSpace ds, Report Report)
44 GenerateDocComment (t, ds, Report);
46 if (t.DefaultStaticConstructor != null)
47 t.DefaultStaticConstructor.GenerateDocComment (t);
49 if (t.InstanceConstructors != null)
50 foreach (Constructor c in t.InstanceConstructors)
51 c.GenerateDocComment (t);
54 foreach (TypeContainer tc in t.Types)
55 tc.GenerateDocComment (t);
57 if (t.Constants != null)
58 foreach (Const c in t.Constants)
59 c.GenerateDocComment (t);
62 foreach (FieldBase f in t.Fields)
63 f.GenerateDocComment (t);
66 foreach (Event e in t.Events)
67 e.GenerateDocComment (t);
69 if (t.Indexers != null)
70 foreach (Indexer ix in t.Indexers)
71 ix.GenerateDocComment (t);
73 if (t.Properties != null)
74 foreach (Property p in t.Properties)
75 p.GenerateDocComment (t);
77 if (t.Methods != null)
78 foreach (MethodOrOperator m in t.Methods)
79 m.GenerateDocComment (t);
81 if (t.Operators != null)
82 foreach (Operator o in t.Operators)
83 o.GenerateDocComment (t);
87 private static readonly string line_head =
88 Environment.NewLine + " ";
90 private static XmlNode GetDocCommentNode (MemberCore mc,
91 string name, Report Report)
93 // FIXME: It could be even optimizable as not
94 // to use XmlDocument. But anyways the nodes
95 // are not kept in memory.
96 XmlDocument doc = RootContext.Documentation.XmlDocumentation;
98 XmlElement el = doc.CreateElement ("member");
99 el.SetAttribute ("name", name);
100 string normalized = mc.DocComment;
101 el.InnerXml = normalized;
102 // csc keeps lines as written in the sources
103 // and inserts formatting indentation (which
104 // is different from XmlTextWriter.Formatting
105 // one), but when a start tag contains an
106 // endline, it joins the next line. We don't
107 // have to follow such a hacky behavior.
109 normalized.Split ('\n');
111 for (int i = 0; i < split.Length; i++) {
112 string s = split [i].TrimEnd ();
116 el.InnerXml = line_head + String.Join (
117 line_head, split, 0, j);
119 } catch (Exception ex) {
120 Report.Warning (1570, 1, mc.Location, "XML comment on `{0}' has non-well-formed XML ({1})", name, ex.Message);
121 XmlComment com = doc.CreateComment (String.Format ("FIXME: Invalid documentation markup was found for member {0}", name));
127 // Generates xml doc comments (if any), and if required,
128 // handle warning report.
130 internal static void GenerateDocComment (MemberCore mc,
131 DeclSpace ds, Report Report)
133 if (mc.DocComment != null) {
134 string name = mc.GetDocCommentName (ds);
136 XmlNode n = GetDocCommentNode (mc, name, Report);
138 XmlElement el = n as XmlElement;
140 mc.OnGenerateDocComment (el);
142 // FIXME: it could be done with XmlReader
143 XmlNodeList nl = n.SelectNodes (".//include");
145 // It could result in current node removal, so prepare another list to iterate.
146 var al = new List<XmlNode> (nl.Count);
147 foreach (XmlNode inc in nl)
149 foreach (XmlElement inc in al)
150 if (!HandleInclude (mc, inc, Report))
151 inc.ParentNode.RemoveChild (inc);
154 // FIXME: it could be done with XmlReader
155 DeclSpace ds_target = mc as DeclSpace;
156 if (ds_target == null)
159 foreach (XmlElement see in n.SelectNodes (".//see"))
160 HandleSee (mc, ds_target, see, Report);
161 foreach (XmlElement seealso in n.SelectNodes (".//seealso"))
162 HandleSeeAlso (mc, ds_target, seealso ,Report);
163 foreach (XmlElement see in n.SelectNodes (".//exception"))
164 HandleException (mc, ds_target, see, Report);
167 n.WriteTo (RootContext.Documentation.XmlCommentOutput);
169 else if (mc.IsExposedFromAssembly ()) {
170 Constructor c = mc as Constructor;
171 if (c == null || !c.IsDefault ())
172 Report.Warning (1591, 4, mc.Location,
173 "Missing XML comment for publicly visible type or member `{0}'", mc.GetSignatureForError ());
178 // Processes "include" element. Check included file and
179 // embed the document content inside this documentation node.
181 private static bool HandleInclude (MemberCore mc, XmlElement el, Report Report)
183 bool keep_include_node = false;
184 string file = el.GetAttribute ("file");
185 string path = el.GetAttribute ("path");
187 Report.Warning (1590, 1, mc.Location, "Invalid XML `include' element. Missing `file' attribute");
188 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Include tag is invalid "), el);
189 keep_include_node = true;
191 else if (path.Length == 0) {
192 Report.Warning (1590, 1, mc.Location, "Invalid XML `include' element. Missing `path' attribute");
193 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Include tag is invalid "), el);
194 keep_include_node = true;
198 if (!RootContext.Documentation.StoredDocuments.TryGetValue (file, out doc)) {
200 doc = new XmlDocument ();
202 RootContext.Documentation.StoredDocuments.Add (file, doc);
203 } catch (Exception) {
204 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (String.Format (" Badly formed XML in at comment file `{0}': cannot be included ", file)), el);
205 Report.Warning (1592, 1, mc.Location, "Badly formed XML in included comments file -- `{0}'", file);
210 XmlNodeList nl = doc.SelectNodes (path);
212 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" No matching elements were found for the include tag embedded here. "), el);
214 keep_include_node = true;
216 foreach (XmlNode n in nl)
217 el.ParentNode.InsertBefore (el.OwnerDocument.ImportNode (n, true), el);
218 } catch (Exception ex) {
219 el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Failed to insert some or all of included XML "), el);
220 Report.Warning (1589, 1, mc.Location, "Unable to include XML fragment `{0}' of file `{1}' ({2})", path, file, ex.Message);
224 return keep_include_node;
228 // Handles <see> elements.
230 private static void HandleSee (MemberCore mc,
231 DeclSpace ds, XmlElement see, Report r)
233 HandleXrefCommon (mc, ds, see, r);
237 // Handles <seealso> elements.
239 private static void HandleSeeAlso (MemberCore mc,
240 DeclSpace ds, XmlElement seealso, Report r)
242 HandleXrefCommon (mc, ds, seealso, r);
246 // Handles <exception> elements.
248 private static void HandleException (MemberCore mc,
249 DeclSpace ds, XmlElement seealso, Report r)
251 HandleXrefCommon (mc, ds, seealso, r);
254 static readonly char [] wsChars =
255 new char [] {' ', '\t', '\n', '\r'};
258 // returns a full runtime type name from a name which might
259 // be C# specific type name.
261 private static TypeSpec FindDocumentedType (MemberCore mc, string name, DeclSpace ds, string cref, Report r)
263 bool is_array = false;
264 string identifier = name;
265 if (name [name.Length - 1] == ']') {
266 string tmp = name.Substring (0, name.Length - 1).Trim (wsChars);
267 if (tmp [tmp.Length - 1] == '[') {
268 identifier = tmp.Substring (0, tmp.Length - 1).Trim (wsChars);
272 TypeSpec t = FindDocumentedTypeNonArray (mc, identifier, ds, cref, r);
273 if (t != null && is_array)
274 t = Import.ImportType (Array.CreateInstance (t.GetMetaInfo (), 0).GetType ());
278 private static TypeSpec FindDocumentedTypeNonArray (MemberCore mc,
279 string identifier, DeclSpace ds, string cref, Report r)
281 switch (identifier) {
283 return TypeManager.int32_type;
285 return TypeManager.uint32_type;
287 return TypeManager.short_type;;
289 return TypeManager.ushort_type;
291 return TypeManager.int64_type;
293 return TypeManager.uint64_type;;
295 return TypeManager.float_type;;
297 return TypeManager.double_type;
299 return TypeManager.char_type;;
301 return TypeManager.decimal_type;;
303 return TypeManager.byte_type;;
305 return TypeManager.sbyte_type;;
307 return TypeManager.object_type;;
309 return TypeManager.bool_type;;
311 return TypeManager.string_type;;
313 return TypeManager.void_type;;
315 FullNamedExpression e = ds.LookupNamespaceOrType (identifier, 0, mc.Location, false);
317 if (!(e is TypeExpr))
321 int index = identifier.LastIndexOf ('.');
325 TypeSpec parent = FindDocumentedType (mc, identifier.Substring (0, index), ds, cref, r);
328 // no need to detect warning 419 here
329 var ts = FindDocumentedMember (mc, parent,
330 identifier.Substring (index + 1),
331 null, ds, out warn, cref, false, null, r) as TypeSpec;
338 // Returns a MemberInfo that is referenced in XML documentation
339 // (by "see" or "seealso" elements).
341 private static MemberSpec FindDocumentedMember (MemberCore mc,
342 TypeSpec type, string member_name, AParametersCollection param_list,
343 DeclSpace ds, out int warning_type, string cref,
344 bool warn419, string name_for_error, Report r)
346 // for (; type != null; type = type.DeclaringType) {
347 var mi = FindDocumentedMemberNoNest (
348 mc, type, member_name, param_list, ds,
349 out warning_type, cref, warn419,
352 return mi; // new FoundMember (type, mi);
358 private static MemberSpec FindDocumentedMemberNoNest (
359 MemberCore mc, TypeSpec type, string member_name,
360 AParametersCollection param_list, DeclSpace ds, out int warning_type,
361 string cref, bool warn419, string name_for_error, Report Report)
364 var filter = new MemberFilter (member_name, 0, MemberKind.All, param_list, null);
365 IList<MemberSpec> found = null;
366 while (type != null && found == null) {
367 found = MemberCache.FindMembers (type, filter, BindingRestriction.None);
368 type = type.DeclaringType;
374 if (warn419 && found.Count > 1) {
375 Report419 (mc, name_for_error, found.ToArray (), Report);
381 if (param_list == null) {
382 // search for fields/events etc.
383 mis = TypeManager.MemberLookup (type, null,
384 type, MemberKind.All,
385 BindingRestriction.None,
387 mis = FilterOverridenMembersOut (mis);
388 if (mis == null || mis.Length == 0)
390 if (warn419 && IsAmbiguous (mis))
391 Report419 (mc, name_for_error, mis, Report);
395 MethodSignature msig = new MethodSignature (member_name, null, param_list);
396 mis = FindMethodBase (type,
397 BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance,
400 if (warn419 && mis.Length > 0) {
401 if (IsAmbiguous (mis))
402 Report419 (mc, name_for_error, mis, Report);
406 // search for operators (whose parameters exactly
407 // matches with the list) and possibly report CS1581.
409 string return_type_name = null;
410 if (member_name.StartsWith ("implicit operator ")) {
411 Operator.GetMetadataName (Operator.OpType.Implicit);
412 return_type_name = member_name.Substring (18).Trim (wsChars);
414 else if (member_name.StartsWith ("explicit operator ")) {
415 oper = Operator.GetMetadataName (Operator.OpType.Explicit);
416 return_type_name = member_name.Substring (18).Trim (wsChars);
418 else if (member_name.StartsWith ("operator ")) {
419 oper = member_name.Substring (9).Trim (wsChars);
421 // either unary or binary
423 oper = param_list.Length == 2 ?
424 Operator.GetMetadataName (Operator.OpType.Addition) :
425 Operator.GetMetadataName (Operator.OpType.UnaryPlus);
428 oper = param_list.Length == 2 ?
429 Operator.GetMetadataName (Operator.OpType.Subtraction) :
430 Operator.GetMetadataName (Operator.OpType.UnaryNegation);
433 oper = Operator.GetMetadataName (oper);
438 Report.Warning (1020, 1, mc.Location, "Overloadable {0} operator is expected", param_list.Length == 2 ? "binary" : "unary");
439 Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
440 mc.GetSignatureForError (), cref);
444 // here we still don't consider return type (to
445 // detect CS1581 or CS1002+CS1584).
446 msig = new MethodSignature (oper, null, param_list);
448 mis = FindMethodBase (type,
449 BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance,
452 return null; // CS1574
454 TypeSpec expected = mi is MethodSpec ?
455 ((MethodSpec) mi).ReturnType :
457 ((PropertySpec) mi).PropertyType :
459 if (return_type_name != null) {
460 TypeSpec returnType = FindDocumentedType (mc, return_type_name, ds, cref, Report);
461 if (returnType == null || returnType != expected) {
463 Report.Warning (1581, 1, mc.Location, "Invalid return type in XML comment cref attribute `{0}'", cref);
472 // Processes "see" or "seealso" elements.
473 // Checks cref attribute.
475 private static void HandleXrefCommon (MemberCore mc,
476 DeclSpace ds, XmlElement xref, Report Report)
478 string cref = xref.GetAttribute ("cref").Trim (wsChars);
479 // when, XmlReader, "if (cref == null)"
480 if (!xref.HasAttribute ("cref"))
482 if (cref.Length == 0)
483 Report.Warning (1001, 1, mc.Location, "Identifier expected");
484 // ... and continue until CS1584.
486 string signature; // "x:" are stripped
487 string name; // method invokation "(...)" are removed
488 string parameters; // method parameter list
490 // When it found '?:' ('T:' 'M:' 'F:' 'P:' 'E:' etc.),
491 // MS ignores not only its member kind, but also
492 // the entire syntax correctness. Nor it also does
493 // type fullname resolution i.e. "T:List(int)" is kept
494 // as T:List(int), not
495 // T:System.Collections.Generic.List<System.Int32>
496 if (cref.Length > 2 && cref [1] == ':')
501 // Also note that without "T:" any generic type
504 int parens_pos = signature.IndexOf ('(');
505 int brace_pos = parens_pos >= 0 ? -1 :
506 signature.IndexOf ('[');
507 if (parens_pos > 0 && signature [signature.Length - 1] == ')') {
508 name = signature.Substring (0, parens_pos).Trim (wsChars);
509 parameters = signature.Substring (parens_pos + 1, signature.Length - parens_pos - 2).Trim (wsChars);
511 else if (brace_pos > 0 && signature [signature.Length - 1] == ']') {
512 name = signature.Substring (0, brace_pos).Trim (wsChars);
513 parameters = signature.Substring (brace_pos + 1, signature.Length - brace_pos - 2).Trim (wsChars);
519 Normalize (mc, ref name, Report);
521 string identifier = GetBodyIdentifierFromName (name);
523 // Check if identifier is valid.
524 // This check is not necessary to mark as error, but
525 // csc specially reports CS1584 for wrong identifiers.
526 string [] name_elems = identifier.Split ('.');
527 for (int i = 0; i < name_elems.Length; i++) {
528 string nameElem = GetBodyIdentifierFromName (name_elems [i]);
530 Normalize (mc, ref nameElem, Report);
531 if (!Tokenizer.IsValidIdentifier (nameElem)
532 && nameElem.IndexOf ("operator") < 0) {
533 Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
534 mc.GetSignatureForError (), cref);
535 xref.SetAttribute ("cref", "!:" + signature);
540 // check if parameters are valid
541 AParametersCollection parameter_types;
542 if (parameters == null)
543 parameter_types = null;
544 else if (parameters.Length == 0)
545 parameter_types = ParametersCompiled.EmptyReadOnlyParameters;
547 string [] param_list = parameters.Split (',');
548 var plist = new List<TypeSpec> ();
549 for (int i = 0; i < param_list.Length; i++) {
550 string param_type_name = param_list [i].Trim (wsChars);
551 Normalize (mc, ref param_type_name, Report);
552 TypeSpec param_type = FindDocumentedType (mc, param_type_name, ds, cref, Report);
553 if (param_type == null) {
554 Report.Warning (1580, 1, mc.Location, "Invalid type for parameter `{0}' in XML comment cref attribute `{1}'",
555 (i + 1).ToString (), cref);
558 plist.Add (param_type);
561 parameter_types = ParametersCompiled.CreateFullyResolved (plist.ToArray ());
564 TypeSpec type = FindDocumentedType (mc, name, ds, cref, Report);
566 // delegate must not be referenced with args
568 || parameter_types == null)) {
569 string result = GetSignatureForDoc (type)
570 + (brace_pos < 0 ? String.Empty : signature.Substring (brace_pos));
571 xref.SetAttribute ("cref", "T:" + result);
575 int period = name.LastIndexOf ('.');
577 string typeName = name.Substring (0, period);
578 string member_name = name.Substring (period + 1);
579 string lookup_name = member_name == "this" ? MemberCache.IndexerNameAlias : member_name;
580 Normalize (mc, ref lookup_name, Report);
581 Normalize (mc, ref member_name, Report);
582 type = FindDocumentedType (mc, typeName, ds, cref, Report);
585 var mi = FindDocumentedMember (mc, type, lookup_name, parameter_types, ds, out warn_result, cref, true, name, Report);
589 // we cannot use 'type' directly
590 // to get its name, since mi
591 // could be from DeclaringType
593 xref.SetAttribute ("cref", GetMemberDocHead (mi) + GetSignatureForDoc (mi.DeclaringType) + "." + member_name + GetParametersFormatted (mi));
594 return; // a member of a type
599 var mi = FindDocumentedMember (mc, ds.PartialContainer.Definition, name, parameter_types, ds, out warn_result, cref, true, name, Report);
604 // we cannot use 'type' directly
605 // to get its name, since mi
606 // could be from DeclaringType
608 xref.SetAttribute ("cref", GetMemberDocHead (mi) + GetSignatureForDoc (mi.DeclaringType) + "." + name + GetParametersFormatted (mi));
609 return; // local member name
613 // It still might be part of namespace name.
614 Namespace ns = ds.NamespaceEntry.NS.GetNamespace (name, false);
616 xref.SetAttribute ("cref", "N:" + ns.GetSignatureForError ());
617 return; // a namespace
619 if (GlobalRootNamespace.Instance.IsNamespace (name)) {
620 xref.SetAttribute ("cref", "N:" + name);
621 return; // a namespace
624 Report.Warning (1574, 1, mc.Location, "XML comment on `{0}' has cref attribute `{1}' that could not be resolved",
625 mc.GetSignatureForError (), cref);
627 xref.SetAttribute ("cref", "!:" + name);
630 static string GetParametersFormatted (MemberSpec mi)
632 var pm = mi as IParametersMember;
633 if (pm == null || pm.Parameters.IsEmpty)
636 AParametersCollection parameters = pm.Parameters;
638 if (parameters == null || parameters.Count == 0)
641 StringBuilder sb = new StringBuilder ();
643 for (int i = 0; i < parameters.Count; i++) {
644 // if (is_setter && i + 1 == parameters.Count)
645 // break; // skip "value".
648 TypeSpec t = parameters.Types [i];
649 sb.Append (GetSignatureForDoc (t));
652 return sb.ToString ();
655 static string GetBodyIdentifierFromName (string name)
657 string identifier = name;
659 if (name.Length > 0 && name [name.Length - 1] == ']') {
660 string tmp = name.Substring (0, name.Length - 1).Trim (wsChars);
661 int last = tmp.LastIndexOf ('[');
663 identifier = tmp.Substring (0, last).Trim (wsChars);
669 static void Report419 (MemberCore mc, string member_name, MemberSpec [] mis, Report Report)
671 Report.Warning (419, 3, mc.Location,
672 "Ambiguous reference in cref attribute `{0}'. Assuming `{1}' but other overloads including `{2}' have also matched",
674 TypeManager.GetFullNameSignature (mis [0]),
675 TypeManager.GetFullNameSignature (mis [1]));
679 // Get a prefix from member type for XML documentation (used
680 // to formalize cref target name).
682 static string GetMemberDocHead (MemberSpec type)
684 if (type is FieldSpec)
686 if (type is MethodSpec)
688 if (type is EventSpec)
690 if (type is PropertySpec)
692 if (type is TypeSpec)
701 // Returns a string that represents the signature for this
702 // member which should be used in XML documentation.
704 public static string GetMethodDocCommentName (MemberCore mc, ParametersCompiled parameters, DeclSpace ds)
706 IParameterData [] plist = parameters.FixedParameters;
707 string paramSpec = String.Empty;
709 StringBuilder psb = new StringBuilder ();
711 foreach (Parameter p in plist) {
712 psb.Append (psb.Length != 0 ? "," : "(");
713 psb.Append (GetSignatureForDoc (parameters.Types [i++]));
714 if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0)
717 paramSpec = psb.ToString ();
720 if (paramSpec.Length > 0)
723 string name = mc is Constructor ? "#ctor" : mc.Name;
724 if (mc.MemberName.IsGeneric)
725 name += "``" + mc.MemberName.CountTypeArguments;
727 string suffix = String.Empty;
728 Operator op = mc as Operator;
730 switch (op.OperatorType) {
731 case Operator.OpType.Implicit:
732 case Operator.OpType.Explicit:
733 suffix = "~" + GetSignatureForDoc (op.ReturnType);
737 return String.Concat (mc.DocCommentHeader, ds.Name, ".", name, paramSpec, suffix);
740 static string GetSignatureForDoc (TypeSpec type)
742 var tp = type as TypeParameterSpec;
744 var prefix = tp.IsMethodOwned ? "``" : "`";
745 return prefix + tp.DeclaredPosition;
748 if (TypeManager.IsGenericType (type)) {
749 string g = type.MemberDefinition.Namespace;
750 if (g != null && g.Length > 0)
752 int idx = type.Name.LastIndexOf ('`');
753 g += (idx < 0 ? type.Name : type.Name.Substring (0, idx)) + '{';
755 foreach (TypeSpec t in TypeManager.GetTypeArguments (type))
756 g += (argpos++ > 0 ? "," : String.Empty) + GetSignatureForDoc (t);
761 string name = type.GetMetaInfo ().FullName != null ? type.GetMetaInfo ().FullName : type.Name;
762 return name.Replace ("+", ".").Replace ('&', '@');
766 // Raised (and passed an XmlElement that contains the comment)
767 // when GenerateDocComment is writing documentation expectedly.
769 // FIXME: with a few effort, it could be done with XmlReader,
770 // that means removal of DOM use.
772 internal static void OnMethodGenerateDocComment (
773 MethodCore mc, XmlElement el, Report Report)
775 var paramTags = new Dictionary<string, string> ();
776 foreach (XmlElement pelem in el.SelectNodes ("param")) {
777 string xname = pelem.GetAttribute ("name");
778 if (xname.Length == 0)
779 continue; // really? but MS looks doing so
780 if (xname != "" && mc.ParameterInfo.GetParameterIndexByName (xname) < 0)
781 Report.Warning (1572, 2, mc.Location, "XML comment on `{0}' has a param tag for `{1}', but there is no parameter by that name",
782 mc.GetSignatureForError (), xname);
783 else if (paramTags.ContainsKey (xname))
784 Report.Warning (1571, 2, mc.Location, "XML comment on `{0}' has a duplicate param tag for `{1}'",
785 mc.GetSignatureForError (), xname);
786 paramTags [xname] = xname;
788 IParameterData [] plist = mc.ParameterInfo.FixedParameters;
789 foreach (Parameter p in plist) {
790 if (paramTags.Count > 0 && !paramTags.ContainsKey (p.Name))
791 Report.Warning (1573, 4, mc.Location, "Parameter `{0}' has no matching param tag in the XML comment for `{1}'",
792 p.Name, mc.GetSignatureForError ());
796 private static void Normalize (MemberCore mc, ref string name, Report Report)
798 if (name.Length > 0 && name [0] == '@')
799 name = name.Substring (1);
800 else if (name == "this")
802 else if (Tokenizer.IsKeyword (name) && !IsTypeName (name))
803 Report.Warning (1041, 1, mc.Location, "Identifier expected. `{0}' is a keyword", name);
806 private static bool IsTypeName (string name)
832 // Implements XML documentation generation.
834 public class Documentation
836 public Documentation (string xml_output_filename)
838 docfilename = xml_output_filename;
839 XmlDocumentation = new XmlDocument ();
840 XmlDocumentation.PreserveWhitespace = false;
843 private string docfilename;
846 // Used to create element which helps well-formedness checking.
848 public XmlDocument XmlDocumentation;
851 // The output for XML documentation.
853 public XmlWriter XmlCommentOutput;
856 // Stores XmlDocuments that are included in XML documentation.
857 // Keys are included filenames, values are XmlDocuments.
859 public Dictionary<string, XmlDocument> StoredDocuments = new Dictionary<string, XmlDocument> ();
862 // Outputs XML documentation comment from tokenized comments.
864 public bool OutputDocComment (string asmfilename, Report Report)
866 XmlTextWriter w = null;
868 w = new XmlTextWriter (docfilename, null);
870 w.Formatting = Formatting.Indented;
871 w.WriteStartDocument ();
872 w.WriteStartElement ("doc");
873 w.WriteStartElement ("assembly");
874 w.WriteStartElement ("name");
875 w.WriteString (Path.ChangeExtension (asmfilename, null));
876 w.WriteEndElement (); // name
877 w.WriteEndElement (); // assembly
878 w.WriteStartElement ("members");
879 XmlCommentOutput = w;
880 GenerateDocComment (Report);
881 w.WriteFullEndElement (); // members
882 w.WriteEndElement ();
883 w.WriteWhitespace (Environment.NewLine);
884 w.WriteEndDocument ();
886 } catch (Exception ex) {
887 Report.Error (1569, "Error generating XML documentation file `{0}' (`{1}')", docfilename, ex.Message);
896 // Fixes full type name of each documented types/members up.
898 public void GenerateDocComment (Report r)
900 TypeContainer root = RootContext.ToplevelTypes;
902 if (root.Types != null)
903 foreach (TypeContainer tc in root.Types)
904 DocUtil.GenerateTypeDocComment (tc, null, r);