[Mono-devel-list] Patch for full-featured mcs /doc support

Marek Safar marek.safar at seznam.cz
Wed Dec 1 07:39:39 EST 2004


Hello,

>Hi,
>
>Miguel asked me to extract /doc specific stuff from large sources,
>so I did that. Now we have new doc.cs and I added some static methods
>that handles the bodies of GenerateDocument() logic. The added members
>are still in class.cs etc, but they are just wrappers (I needed them
>not to make method overrides into complicated code).
>  
>
I don't like classes where all methods are static, especially when they
accept same arguments.

Marek

>
>  
>
>------------------------------------------------------------------------
>
>Index: cs-tokenizer.cs
>===================================================================
>--- cs-tokenizer.cs	(revision 36885)
>+++ cs-tokenizer.cs	(working copy)
>@@ -42,6 +42,17 @@
> 		bool handle_assembly = false;
> 
> 		//
>+		// XML documentation buffer. The save point is used to divide
>+		// comments on types and comments on members.
>+		//
>+		StringBuilder xml_comment_buffer;
>+
>+		//
>+		// See comment on XmlCommentState enumeration.
>+		//
>+		XmlCommentState xmlDocState = XmlCommentState.Allowed;
>+
>+		//
> 		// Whether tokens have been seen on this line
> 		//
> 		bool tokens_seen = false;
>@@ -132,6 +143,18 @@
> 				handle_remove_add = value;
> 			}
> 		}
>+
>+		public XmlCommentState doc_state {
>+			get { return xmlDocState; }
>+			set {
>+				if (value == XmlCommentState.Allowed) {
>+					check_incorrect_doc_comment ();
>+					consume_doc_comment ();
>+				}
>+				xmlDocState = value;
>+			}
>+		}
>+
> 		
> 		//
> 		// Class variables
>@@ -362,6 +385,8 @@
> 					define (def);
> 			}
> 
>+			xml_comment_buffer = new StringBuilder ();
>+
> 			//
> 			// FIXME: This could be `Location.Push' but we have to
> 			// find out why the MS compiler allows this
>@@ -411,6 +436,9 @@
> 			case '}':
> 				return Token.CLOSE_BRACE;
> 			case '[':
>+				// To block doccomment inside attribute declaration.
>+				if (doc_state == XmlCommentState.Allowed)
>+					doc_state = XmlCommentState.NotAllowed;
> 				return Token.OPEN_BRACKET;
> 			case ']':
> 				return Token.CLOSE_BRACKET;
>@@ -1741,6 +1769,15 @@
> 		{
> 			int res = consume_identifier (s, false);
> 
>+			if (doc_state == XmlCommentState.Allowed)
>+				doc_state = XmlCommentState.NotAllowed;
>+			switch (res) {
>+			case Token.USING:
>+			case Token.NAMESPACE:
>+				check_incorrect_doc_comment ();
>+				break;
>+			}
>+
> 			if (res == Token.PARTIAL) {
> 				// Save current position and parse next token.
> 				int old = reader.Position;
>@@ -1862,6 +1899,13 @@
> 				
> 					if (d == '/'){
> 						getChar ();
>+						if (RootContext.Documentation != null && peekChar () == '/') {
>+							getChar ();
>+							if (doc_state == XmlCommentState.Allowed)
>+								handle_one_line_xml_comment ();
>+							else if (doc_state == XmlCommentState.NotAllowed)
>+								warn_incorrect_doc_comment ();
>+						}
> 						while ((d = getChar ()) != -1 && (d != '\n') && d != '\r')
> 							col++;
> 						if (d == '\n'){
>@@ -1874,13 +1918,35 @@
> 						continue;
> 					} else if (d == '*'){
> 						getChar ();
>+						bool docAppend = false;
>+						if (RootContext.Documentation != null && peekChar () == '*') {
>+							getChar ();
>+							// But when it is /**/, just do nothing.
>+							if (peekChar () == '/') {
>+								getChar ();
>+								continue;
>+							}
>+							if (doc_state == XmlCommentState.Allowed)
>+								docAppend = true;
>+							else if (doc_state == XmlCommentState.NotAllowed)
>+								warn_incorrect_doc_comment ();
>+						}
> 
>+						int currentCommentStart = 0;
>+						if (docAppend) {
>+							currentCommentStart = xml_comment_buffer.Length;
>+							xml_comment_buffer.Append (Environment.NewLine);
>+						}
>+
> 						while ((d = getChar ()) != -1){
> 							if (d == '*' && peekChar () == '/'){
> 								getChar ();
> 								col++;
> 								break;
> 							}
>+							if (docAppend)
>+								xml_comment_buffer.Append ((char) d);
>+							
> 							if (d == '\n'){
> 								line++;
> 								ref_line++;
>@@ -1889,6 +1955,8 @@
> 								tokens_seen = false;
> 							}
> 						}
>+						if (docAppend)
>+							update_formatted_doc_comment (currentCommentStart);
> 						continue;
> 					}
> 					goto is_punct_label;
>@@ -2037,6 +2105,97 @@
> 			return Token.EOF;
> 		}
> 
>+		//
>+		// Handles one line xml comment
>+		//
>+		private void handle_one_line_xml_comment ()
>+		{
>+			int c;
>+			while ((c = peekChar ()) == ' ')
>+				getChar (); // skip heading whitespaces.
>+			while ((c = peekChar ()) != -1 && (c != '\n') && c != '\r') {
>+				col++;
>+				xml_comment_buffer.Append ((char) getChar ());
>+			}
>+			if (c == '\r') {
>+				getChar ();
>+				xml_comment_buffer.Append ('\r');
>+				if (peekChar () == '\n')
>+					xml_comment_buffer.Append ('\n');
>+			}
>+			else if (c == '\n')
>+				xml_comment_buffer.Append ('\n');
>+		}
>+
>+		//
>+		// Remove heading "*" in Javadoc-like xml documentation.
>+		//
>+		private void update_formatted_doc_comment (int currentCommentStart)
>+		{
>+			int length = xml_comment_buffer.Length - currentCommentStart;
>+			string [] lines = xml_comment_buffer.ToString (
>+				currentCommentStart,
>+				length).Split ('\n');
>+			// The first line starts with /**, thus it is not target
>+			// for the format check.
>+			for (int i = 1; i < lines.Length; i++) {
>+				string s = lines [i];
>+				int idx = s.IndexOf ('*');
>+				string head = null;
>+				if (idx < 0) {
>+					if (i < lines.Length - 1)
>+						return;
>+					head = s;
>+				}
>+				else
>+					head = s.Substring (0, idx);
>+				foreach (char c in head)
>+					if (c != ' ')
>+						return;
>+				lines [i] = s.Substring (idx + 1);
>+			}
>+			xml_comment_buffer.Remove (currentCommentStart, length);
>+			xml_comment_buffer.Insert (
>+				currentCommentStart,
>+				String.Join ("\n", lines));
>+		}
>+
>+		//
>+		// Checks if there was incorrect doc comments and raise
>+		// warnings.
>+		//
>+		public void check_incorrect_doc_comment ()
>+		{
>+			if (xml_comment_buffer.Length > 0)
>+				warn_incorrect_doc_comment ();
>+		}
>+
>+		//
>+		// Raises a warning when tokenizer found incorrect doccomment
>+		// markup.
>+		//
>+		private void warn_incorrect_doc_comment ()
>+		{
>+			doc_state = XmlCommentState.Error;
>+			// in csc, it is 'XML comment is not placed on a valid 
>+			// language element'. But that does not make sense.
>+			Report.Warning (1587, 2, Location, "XML comment is placed on an invalid language element which can not accept it.");
>+		}
>+
>+		//
>+		// Consumes the saved xml comment lines (if any)
>+		// as for current target member or type.
>+		//
>+		public string consume_doc_comment ()
>+		{
>+			if (xml_comment_buffer.Length > 0) {
>+				string ret = xml_comment_buffer.ToString ();
>+				xml_comment_buffer.Length = 0;
>+				return ret;
>+			}
>+			return null;
>+		}
>+
> 		public void cleanup ()
> 		{
> 			if (ifstack != null && ifstack.Count >= 1) {
>@@ -2049,4 +2208,18 @@
> 				
> 		}
> 	}
>+
>+	//
>+	// Indicates whether it accepts XML documentation or not.
>+	//
>+	public enum XmlCommentState {
>+		// comment is allowed in this state.
>+		Allowed,
>+		// comment is not allowed in this state.
>+		NotAllowed,
>+		// once comments appeared when it is NotAllowed, then the
>+		// state is changed to it, until the state is changed to
>+		// .Allowed.
>+		Error
>+	}
> }
>Index: mcs.exe.sources
>===================================================================
>--- mcs.exe.sources	(revision 36885)
>+++ mcs.exe.sources	(working copy)
>@@ -12,6 +12,7 @@
> convert.cs
> decl.cs
> delegate.cs
>+doc.cs
> enum.cs
> ecore.cs
> expression.cs
>Index: rootcontext.cs
>===================================================================
>--- rootcontext.cs	(revision 36885)
>+++ rootcontext.cs	(working copy)
>@@ -13,6 +13,7 @@
> using System.Reflection;
> using System.Reflection.Emit;
> using System.Diagnostics;
>+using System.Xml;
> 
> namespace Mono.CSharp {
> 
>@@ -80,6 +81,11 @@
> 		public static bool StrongNameDelaySign = false;
> 
> 		//
>+		// If set, enable XML documentation generation
>+		//
>+		public static Documentation Documentation;
>+
>+		//
> 		// Constructor
> 		//
> 		static RootContext ()
>Index: class.cs
>===================================================================
>--- class.cs	(revision 36885)
>+++ class.cs	(working copy)
>@@ -40,6 +40,7 @@
> using System.Security;
> using System.Security.Permissions;
> using System.Text;
>+using System.Xml;
> 
> using Mono.CompilerServices.SymbolWriter;
> 
>@@ -432,7 +433,7 @@
> 		// Pointers to the default constructor and the default static constructor
> 		//
> 		protected Constructor default_constructor;
>-		protected Constructor default_static_constructor;
>+		public Constructor default_static_constructor;
> 
> 		//
> 		// Whether we have at least one non-static field
>@@ -2396,6 +2397,19 @@
> 			return FindMembers (mt, bf | BindingFlags.DeclaredOnly, null, null);
> 		}
> 
>+		//
>+		// Generates xml doc comments (if any), and if required,
>+		// handle warning report.
>+		//
>+		internal override void GenerateDocComment (DeclSpace ds)
>+		{
>+			DocUtil.GenerateTypeDocComment (this, ds);
>+		}
>+
>+		public override string DocCommentHeader {
>+			get { return "T:"; }
>+		}
>+
> 		public virtual MemberCache ParentCache {
> 			get {
> 				return parent_cache;
>@@ -3296,6 +3310,34 @@
> 			return true;
> 		}
> 
>+		//
>+		// Returns a string that represents the signature for this 
>+		// member which should be used in XML documentation.
>+		//
>+		public override string GetDocCommentName (DeclSpace ds)
>+		{
>+			return DocUtil.GetMethodDocCommentName (this, ds);
>+		}
>+
>+		//
>+		// Raised (and passed an XmlElement that contains the comment)
>+		// when GenerateDocComment is writing documentation expectedly.
>+		//
>+		// FIXME: with a few effort, it could be done with XmlReader,
>+		// that means removal of DOM use.
>+		//
>+		internal override void OnGenerateDocComment (DeclSpace ds, XmlElement el)
>+		{
>+			DocUtil.OnMethodGenerateDocComment (this, ds, el);
>+		}
>+
>+		//
>+		//   Represents header string for documentation comment.
>+		//
>+		public override string DocCommentHeader {
>+			get { return "M:"; }
>+		}
>+
> 		protected override void VerifyObsoleteAttribute()
> 		{
> 			base.VerifyObsoleteAttribute ();
>@@ -5224,6 +5266,13 @@
> 
> 			base.Emit ();
> 		}
>+
>+		//
>+		//   Represents header string for documentation comment.
>+		//
>+		public override string DocCommentHeader {
>+			get { return "F:"; }
>+		}
> 	}
> 
> 	//
>@@ -5532,6 +5581,13 @@
> 			}
> 		}
> 
>+		//
>+		//   Represents header string for documentation comment.
>+		//
>+		public override string DocCommentHeader {
>+			get { throw new InvalidOperationException ("Unexpected attempt to get doc comment from " + this.GetType () + "."); }
>+		}
>+
> 		protected override void VerifyObsoleteAttribute()
> 		{
> 		}
>@@ -5982,6 +6038,13 @@
> 				return attribute_targets;
> 			}
> 		}
>+
>+		//
>+		//   Represents header string for documentation comment.
>+		//
>+		public override string DocCommentHeader {
>+			get { return "P:"; }
>+		}
> 	}
> 			
> 	public class Property : PropertyBase, IIteratorContainer {
>@@ -6626,6 +6689,13 @@
> 
> 			return TypeManager.GetFullNameSignature (EventBuilder);
> 		}
>+
>+		//
>+		//   Represents header string for documentation comment.
>+		//
>+		public override string DocCommentHeader {
>+			get { return "E:"; }
>+		}
> 	}
> 
> 
>Index: decl.cs
>===================================================================
>--- decl.cs	(revision 36885)
>+++ decl.cs	(working copy)
>@@ -16,6 +16,7 @@
> using System.Globalization;
> using System.Reflection.Emit;
> using System.Reflection;
>+using System.Xml;
> 
> namespace Mono.CSharp {
> 
>@@ -138,6 +139,17 @@
> 		/// </summary>
> 		public readonly Location Location;
> 
>+		/// <summary>
>+		///   XML documentation comment
>+		/// </summary>
>+		public string DocComment;
>+
>+		/// <summary>
>+		///   Represents header string for documentation comment 
>+		///   for each member types.
>+		/// </summary>
>+		public abstract string DocCommentHeader { get; }
>+
> 		[Flags]
> 		public enum Flags {
> 			Obsolete_Undetected = 1,		// Obsolete attribute has not been detected yet
>@@ -292,7 +304,7 @@
> 		/// <summary>
> 		/// Returns true when MemberCore is exposed from assembly.
> 		/// </summary>
>-		protected bool IsExposedFromAssembly (DeclSpace ds)
>+		public bool IsExposedFromAssembly (DeclSpace ds)
> 		{
> 			if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
> 				return false;
>@@ -364,6 +376,34 @@
> 
> 		protected abstract void VerifyObsoleteAttribute ();
> 
>+		//
>+		// Raised (and passed an XmlElement that contains the comment)
>+		// when GenerateDocComment is writing documentation expectedly.
>+		//
>+		internal virtual void OnGenerateDocComment (DeclSpace ds, XmlElement intermediateNode)
>+		{
>+		}
>+
>+		//
>+		// Returns a string that represents the signature for this 
>+		// member which should be used in XML documentation.
>+		//
>+		public virtual string GetDocCommentName (DeclSpace ds)
>+		{
>+			if (ds == null || this is DeclSpace)
>+				return DocCommentHeader + Name;
>+			else
>+				return String.Concat (DocCommentHeader, ds.Name, ".", Name);
>+		}
>+
>+		//
>+		// Generates xml doc comments (if any), and if required,
>+		// handle warning report.
>+		//
>+		internal virtual void GenerateDocComment (DeclSpace ds)
>+		{
>+			DocUtil.GenerateDocComment (this, ds);
>+		}
> 	}
> 
> 	/// <summary>
>@@ -1326,7 +1366,7 @@
> 			IDictionaryEnumerator it = parent.member_hash.GetEnumerator ();
> 			while (it.MoveNext ()) {
> 				hash [it.Key] = ((ArrayList) it.Value).Clone ();
>-                        }
>+			 }
>                                 
> 			return hash;
> 		}
>Index: delegate.cs
>===================================================================
>--- delegate.cs	(revision 36885)
>+++ delegate.cs	(working copy)
>@@ -643,6 +643,13 @@
> 			}
> 		}
> 
>+		//
>+		//   Represents header string for documentation comment.
>+		//
>+		public override string DocCommentHeader {
>+			get { return "T:"; }
>+		}
>+
> 		protected override void VerifyObsoleteAttribute()
> 		{
> 			CheckUsageOfObsoleteAttribute (ret_type);
>Index: cs-parser.jay
>===================================================================
>--- cs-parser.jay	(revision 36885)
>+++ cs-parser.jay	(working copy)
>@@ -81,6 +81,14 @@
> 		/// The current file.
> 		///
> 		SourceFile file;
>+
>+		///
>+		/// Temporary Xml documentation cache.
>+		/// For enum types, we need one more temporary store.
>+		///
>+		string tmpComment;
>+		string enumTypeComment;
>+
> 		
> 		
> 		/// Current attribute target
>@@ -284,7 +292,13 @@
> 	
> opt_EOF
> 	: /* empty */
>+	{
>+		Lexer.check_incorrect_doc_comment ();
>+	}
> 	| EOF
>+	{
>+		Lexer.check_incorrect_doc_comment ();
>+	}
> 	;
> 
> outer_declarations
>@@ -304,7 +318,15 @@
> 
> using_directive
> 	: using_alias_directive
>+	{
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+	}
> 	| using_namespace_directive
>+	{
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+	}
> 	;
> 
> using_alias_directive
>@@ -375,6 +397,10 @@
> 
> namespace_body
> 	: OPEN_BRACE
>+	  {
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+	  }
> 	  opt_using_directives
> 	  opt_namespace_member_declarations
> 	  CLOSE_BRACE
>@@ -491,6 +517,13 @@
> 			} else {
> 				$$ = new Attributes (sect);
> 			}
>+			if ($$ == null) {
>+				if (RootContext.Documentation != null) {
>+					Lexer.check_incorrect_doc_comment ();
>+					Lexer.doc_state =
>+						XmlCommentState.Allowed;
>+				}
>+			}
> 		} else {
> 			$$ = new Attributes (sect);
> 		}		
>@@ -746,9 +779,16 @@
> 		if ($7 != null)
> 			current_class.Bases = (ArrayList) $7;
> 
>+		if (RootContext.Documentation != null)
>+			current_class.DocComment = Lexer.consume_doc_comment ();
>+
> 		current_class.Register ();
> 	  }
> 	  struct_body
>+	  {
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+	  }
> 	  opt_semicolon
> 	  {
> 		$$ = current_class;
>@@ -762,7 +802,12 @@
> 	;
> 
> struct_body
>-	: OPEN_BRACE opt_struct_member_declarations CLOSE_BRACE
>+	: OPEN_BRACE
>+	  {
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+	  }
>+	  opt_struct_member_declarations CLOSE_BRACE
> 	;
> 
> opt_struct_member_declarations
>@@ -814,6 +859,10 @@
> 				(Expression) constant.expression_or_array_initializer, modflags, 
> 				(Attributes) $1, l);
> 
>+			if (RootContext.Documentation != null) {
>+				c.DocComment = Lexer.consume_doc_comment ();
>+				Lexer.doc_state = XmlCommentState.Allowed;
>+			}
> 			current_container.AddConstant (c);
> 		}
> 	  }
>@@ -866,6 +915,10 @@
> 						 var.expression_or_array_initializer, 
> 						 (Attributes) $1, l);
> 
>+			if (RootContext.Documentation != null) {
>+				field.DocComment = Lexer.consume_doc_comment ();
>+				Lexer.doc_state = XmlCommentState.Allowed;
>+			}
> 			current_container.AddField (field);
> 		}
> 	  }
>@@ -927,6 +980,8 @@
> method_declaration
> 	: method_header {
> 		iterator_container = (IIteratorContainer) $1;
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.NotAllowed;
> 	  }
> 	  method_body
> 	  {
>@@ -953,6 +1008,9 @@
> 
> 		current_local_parameters = null;
> 		iterator_container = null;
>+
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
> 	  }
> 	;
> 
>@@ -989,6 +1047,9 @@
> 
> 		current_local_parameters = (Parameters) $6;
> 
>+		if (RootContext.Documentation != null)
>+			method.DocComment = Lexer.consume_doc_comment ();
>+
> 		$$ = method;
> 	  }
> 	| opt_attributes
>@@ -1003,6 +1064,10 @@
> 					    (Attributes) $1, lexer.Location);
> 
> 		current_local_parameters = (Parameters) $6;
>+
>+		if (RootContext.Documentation != null)
>+			method.DocComment = Lexer.consume_doc_comment ();
>+
> 		$$ = method;
> 	  }
> 	| opt_attributes
>@@ -1020,6 +1085,10 @@
> 					    lexer.Location);
> 
> 		current_local_parameters = (Parameters) $7;
>+
>+		if (RootContext.Documentation != null)
>+			method.DocComment = Lexer.consume_doc_comment ();
>+
> 		$$ = method;
> 	  }
> 	;
>@@ -1163,7 +1232,12 @@
> property_declaration
> 	: opt_attributes
> 	  opt_modifiers
>-	  type namespace_or_type_name
>+	  type
>+	  namespace_or_type_name
>+	  {
>+		if (RootContext.Documentation != null)
>+			tmpComment = Lexer.consume_doc_comment ();
>+	  }
> 	  OPEN_BRACE 
> 	  {
> 		implicit_value_parameter_type = (Expression) $3;
>@@ -1181,11 +1255,11 @@
> 	  CLOSE_BRACE
> 	  { 
> 		Property prop;
>-		Pair pair = (Pair) $7;
>+		Pair pair = (Pair) $8;
> 		Accessor get_block = (Accessor) pair.First;
> 		Accessor set_block = (Accessor) pair.Second;
> 
>-		Location loc = (Location) $6;
>+		Location loc = (Location) $7;
> 		MemberName name = (MemberName) $4;
> 
> 		prop = new Property (current_class, (Expression) $3, (int) $2, false,
>@@ -1196,6 +1270,10 @@
> 		current_container.AddProperty (prop);
> 		implicit_value_parameter_type = null;
> 		iterator_container = null;
>+
>+		if (RootContext.Documentation != null)
>+			prop.DocComment = ConsumeStoredComment ();
>+
> 	  }
> 	;
> 
>@@ -1236,6 +1314,10 @@
> 		$$ = new Accessor ((ToplevelBlock) $5, (int) $2, (Attributes) $1, lexer.Location);
> 		current_local_parameters = null;
> 		lexer.PropertyParsing = true;
>+
>+		if (RootContext.Documentation != null)
>+			if (Lexer.doc_state == XmlCommentState.Error)
>+				Lexer.doc_state = XmlCommentState.NotAllowed;
> 	  }
> 	;
> 
>@@ -1273,6 +1355,10 @@
> 		$$ = new Accessor ((ToplevelBlock) $5, (int) $2, (Attributes) $1, lexer.Location);
> 		current_local_parameters = null;
> 		lexer.PropertyParsing = true;
>+
>+		if (RootContext.Documentation != null
>+			&& Lexer.doc_state == XmlCommentState.Error)
>+			Lexer.doc_state = XmlCommentState.NotAllowed;
> 	  }
> 	;
> 
>@@ -1310,6 +1396,11 @@
> 	  {
> 		current_class.Bases = (ArrayList) $7;
> 
>+		if (RootContext.Documentation != null) {
>+			current_class.DocComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
>+
> 		current_class.Register ();
> 	  }
> 	  interface_body 
>@@ -1470,6 +1561,8 @@
> 				  new MemberName (TypeContainer.DefaultIndexerName),
> 				  (int) $2, true, (Parameters) $6, (Attributes) $1,
> 				  info.Get, info.Set, lexer.Location);
>+		if (RootContext.Documentation != null)
>+			((Indexer) $$).DocComment = ConsumeStoredComment ();
> 	  }
> 	;
> 
>@@ -1493,6 +1586,9 @@
> 			new Parameters (param_list, null, decl.location),
> 			(ToplevelBlock) $5, (Attributes) $1, decl.location);
> 
>+		if (RootContext.Documentation != null)
>+			op.DocComment = ConsumeStoredComment ();
>+
> 		if (SimpleIteratorContainer.Simple.Yields)
> 			op.SetYields ();
> 
>@@ -1522,12 +1618,18 @@
> 			op = Operator.OpType.UnaryNegation;
> 
> 		Parameter [] pars = new Parameter [1];
>+		Expression type = (Expression) $5;
> 
>-		pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null);
>+		pars [0] = new Parameter (type, (string) $6, Parameter.Modifier.NONE, null);
> 
> 		current_local_parameters = new Parameters (pars, null, lexer.Location);
> 
>-		$$ = new OperatorDeclaration (op, (Expression) $1, (Expression) $5, (string) $6,
>+		if (RootContext.Documentation != null) {
>+			tmpComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
>+
>+		$$ = new OperatorDeclaration (op, (Expression) $1, type, (string) $6,
> 					      null, null, lexer.Location);
> 	}
> 	| type OPERATOR overloadable_operator
>@@ -1536,18 +1638,26 @@
> 	  	type IDENTIFIER 
> 	  CLOSE_PARENS
>         {
>-	       CheckBinaryOperator ((Operator.OpType) $3);
>+		CheckBinaryOperator ((Operator.OpType) $3);
> 
>-	       Parameter [] pars = new Parameter [2];
>+		Parameter [] pars = new Parameter [2];
> 
>-	       pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null);
>-	       pars [1] = new Parameter ((Expression) $8, (string) $9, Parameter.Modifier.NONE, null);
>+		Expression typeL = (Expression) $5;
>+		Expression typeR = (Expression) $8;
> 
>+	       pars [0] = new Parameter (typeL, (string) $6, Parameter.Modifier.NONE, null);
>+	       pars [1] = new Parameter (typeR, (string) $9, Parameter.Modifier.NONE, null);
>+
> 	       current_local_parameters = new Parameters (pars, null, lexer.Location);
>+
>+		if (RootContext.Documentation != null) {
>+			tmpComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
> 	       
> 	       $$ = new OperatorDeclaration ((Operator.OpType) $3, (Expression) $1, 
>-					     (Expression) $5, (string) $6,
>-					     (Expression) $8, (string) $9, lexer.Location);
>+					     typeL, (string) $6,
>+					     typeR, (string) $9, lexer.Location);
>         }
> 	| conversion_operator_declarator
> 	;
>@@ -1624,6 +1734,9 @@
> 		c.OptAttributes = (Attributes) $1;
> 		c.ModFlags = (int) $2;
> 	
>+		if (RootContext.Documentation != null)
>+			c.DocComment = ConsumeStoredComment ();
>+
> 		if (c.Name == current_container.Basename){
> 			if ((c.ModFlags & Modifiers.STATIC) != 0){
> 				if ((c.ModFlags & Modifiers.Accessibility) != 0){
>@@ -1657,22 +1770,30 @@
> 		current_container.AddConstructor (c);
> 
> 		current_local_parameters = null;
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
> 	  }
> 	;
> 
> constructor_declarator
>-	: IDENTIFIER 
>+	: IDENTIFIER
>+	  {
>+		if (RootContext.Documentation != null) {
>+			tmpComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
>+	  }
> 	  OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS 
> 	  {
> 		oob_stack.Push (lexer.Location);
> 
>-		current_local_parameters = (Parameters) $3;
>+		current_local_parameters = (Parameters) $4;
> 	  }
> 	  opt_constructor_initializer
> 	  {
> 		Location l = (Location) oob_stack.Pop ();
>-		$$ = new Constructor (current_class, (string) $1, 0, (Parameters) $3,
>-				      (ConstructorInitializer) $6, l);
>+		$$ = new Constructor (current_class, (string) $1, 0, (Parameters) $4,
>+				      (ConstructorInitializer) $7, l);
> 	  }
> 	;
> 
>@@ -1708,9 +1829,16 @@
>         ;
>         
> destructor_declaration
>-	: opt_attributes opt_finalizer TILDE IDENTIFIER OPEN_PARENS CLOSE_PARENS block
>+	: opt_attributes opt_finalizer TILDE 
> 	  {
>-		if ((string) $4 != current_container.Basename){
>+		if (RootContext.Documentation != null) {
>+			tmpComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.NotAllowed;
>+		}
>+	  }
>+	  IDENTIFIER OPEN_PARENS CLOSE_PARENS block
>+	  {
>+		if ((string) $5 != current_container.Basename){
> 			Report.Error (574, lexer.Location, "Name of destructor must match name of class");
> 		} else if (!(current_container is Class)){
> 			Report.Error (575, lexer.Location, "Destructors are only allowed in class types");
>@@ -1734,8 +1862,10 @@
> 			Method d = new Destructor (
> 				current_class, TypeManager.system_void_expr, m, "Finalize", 
> 				new Parameters (null, null, l), (Attributes) $1, l);
>+			if (RootContext.Documentation != null)
>+				d.DocComment = ConsumeStoredComment ();
> 		  
>-			d.Block = (ToplevelBlock) $7;
>+			d.Block = (ToplevelBlock) $8;
> 			current_container.AddMethod (d);
> 		}
> 	  }
>@@ -1756,7 +1886,11 @@
> 				lexer.Location);
> 
> 			current_container.AddEvent (e);
>-				       
>+
>+			if (RootContext.Documentation != null) {
>+				e.DocComment = Lexer.consume_doc_comment ();
>+				Lexer.doc_state = XmlCommentState.Allowed;
>+			}
> 		}
> 	  }
> 	| opt_attributes
>@@ -1788,7 +1922,11 @@
> 				current_class, (Expression) $4, (int) $2, false, name, null,
> 				(Attributes) $1, (Accessor) pair.First, (Accessor) pair.Second,
> 				loc);
>-			
>+			if (RootContext.Documentation != null) {
>+				e.DocComment = Lexer.consume_doc_comment ();
>+				Lexer.doc_state = XmlCommentState.Allowed;
>+			}
>+
> 			current_container.AddEvent (e);
> 			implicit_value_parameter_type = null;
> 		}
>@@ -1800,6 +1938,9 @@
> 			Report.Error (71, lexer.Location, "Explicit implementation of events requires property syntax");
> 		else 
> 			Report.Error (71, lexer.Location, "Event declaration should use property syntax");
>+
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
> 	  }
> 	;
> 
>@@ -1910,6 +2051,8 @@
> 		indexer = new Indexer (current_class, decl.type, name,
> 				       (int) $2, false, decl.param_list, (Attributes) $1,
> 				       get_block, set_block, loc);
>+		if (RootContext.Documentation != null)
>+			indexer.DocComment = ConsumeStoredComment ();
> 
> 		current_container.AddIndexer (indexer);
> 		
>@@ -1929,6 +2072,10 @@
> 		} else if (pars.FixedParameters == null && pars.ArrayParameter == null){
> 			Report.Error (1551, lexer.Location, "Indexers must have at least one parameter");
> 		}
>+		if (RootContext.Documentation != null) {
>+			tmpComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
> 
> 		$$ = new IndexerDeclaration ((Expression) $1, null, pars);
> 	  }
>@@ -1942,8 +2089,14 @@
> 		} else if (pars.FixedParameters == null && pars.ArrayParameter == null){
> 			Report.Error (1551, lexer.Location, "Indexers must have at least one parameter");
> 		}
>+
> 		MemberName name = (MemberName) $2;
> 		$$ = new IndexerDeclaration ((Expression) $1, name, pars);
>+
>+		if (RootContext.Documentation != null) {
>+			tmpComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
> 	  }
> 	;
> 
>@@ -1951,7 +2104,10 @@
> 	: opt_attributes
> 	  opt_modifiers
> 	  ENUM IDENTIFIER 
>-	  opt_enum_base
>+	  opt_enum_base {
>+		if (RootContext.Documentation != null)
>+			enumTypeComment = Lexer.consume_doc_comment ();
>+	  }
> 	  enum_body
> 	  opt_semicolon
> 	  { 
>@@ -1961,10 +2117,14 @@
> 		Enum e = new Enum (current_namespace, current_container, (Expression) $5, (int) $2,
> 				   full_name, (Attributes) $1, enum_location);
> 		
>-		foreach (VariableDeclaration ev in (ArrayList) $6) {
>+		if (RootContext.Documentation != null)
>+			e.DocComment = enumTypeComment;
>+
>+		foreach (VariableDeclaration ev in (ArrayList) $7) {
> 			e.AddEnumMember (ev.identifier, 
> 					 (Expression) ev.expression_or_array_initializer,
>-					 ev.Location, ev.OptAttributes);
>+					 ev.Location, ev.OptAttributes,
>+					 ev.DocComment);
> 		}
> 
> 		string name = full_name.GetName ();
>@@ -1980,10 +2140,21 @@
> 	;
> 
> enum_body
>-	: OPEN_BRACE opt_enum_member_declarations CLOSE_BRACE
>+	: OPEN_BRACE
> 	  {
>-		$$ = $2;
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
> 	  }
>+	  opt_enum_member_declarations
>+	  {
>+	  	// here will be evaluated after CLOSE_BLACE is consumed.
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+	  }
>+	  CLOSE_BRACE
>+	  {
>+		$$ = $3;
>+	  }
> 	;
> 
> opt_enum_member_declarations
>@@ -2012,15 +2183,31 @@
> enum_member_declaration
> 	: opt_attributes IDENTIFIER 
> 	  {
>-		$$ = new VariableDeclaration ((string) $2, null, lexer.Location, (Attributes) $1);
>+		VariableDeclaration vd = new VariableDeclaration ((string) $2, null, lexer.Location, (Attributes) $1);
>+
>+		if (RootContext.Documentation != null) {
>+			vd.DocComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
>+
>+		$$ = vd;
> 	  }
> 	| opt_attributes IDENTIFIER
> 	  {
>-		  $$ = lexer.Location;
>+		$$ = lexer.Location;
>+		if (RootContext.Documentation != null) {
>+			tmpComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.NotAllowed;
>+		}
> 	  }
>           ASSIGN expression
> 	  { 
>-		$$ = new VariableDeclaration ((string) $2, $5, lexer.Location, (Attributes) $1);
>+		VariableDeclaration vd = new VariableDeclaration ((string) $2, $5, lexer.Location, (Attributes) $1);
>+
>+		if (RootContext.Documentation != null)
>+			vd.DocComment = ConsumeStoredComment ();
>+
>+		$$ = vd;
> 	  }
> 	;
> 
>@@ -2036,6 +2223,11 @@
> 		Delegate del = new Delegate (current_namespace, current_container, (Expression) $4,
> 					     (int) $2, name, (Parameters) $7, (Attributes) $1, l);
> 
>+		if (RootContext.Documentation != null) {
>+			del.DocComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
>+
> 		current_container.AddDelegate (del);
> 		RootContext.Tree.RecordDecl (name.GetName (true), del);
> 	  }	
>@@ -2052,6 +2244,11 @@
> 			TypeManager.system_void_expr, (int) $2, name,
> 			(Parameters) $7, (Attributes) $1, l);
> 
>+		if (RootContext.Documentation != null) {
>+			del.DocComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
>+
> 		current_container.AddDelegate (del);
> 		RootContext.Tree.RecordDecl (name.GetName (true), del);
> 	  }
>@@ -3055,9 +3252,18 @@
> 			current_class.Bases = (ArrayList) $7;
> 		}
> 
>+		if (RootContext.Documentation != null) {
>+			current_class.DocComment = Lexer.consume_doc_comment ();
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+		}
>+
> 		current_class.Register ();
> 	  }
>-	  class_body 
>+	  class_body
>+	  {
>+		if (RootContext.Documentation != null)
>+			Lexer.doc_state = XmlCommentState.Allowed;
>+	  }
> 	  opt_semicolon 
> 	  {
> 		$$ = current_class;
>@@ -4138,6 +4344,7 @@
> 	public object expression_or_array_initializer;
> 	public Location Location;
> 	public Attributes OptAttributes;
>+	public string DocComment;
> 
> 	public VariableDeclaration (string id, object eoai, Location l, Attributes opt_attrs)
> 	{
>@@ -4482,5 +4689,13 @@
> 	CheckToken (1041, yyToken, "Identifier expected");
> }
> 
>+string ConsumeStoredComment ()
>+{
>+	string s = tmpComment;
>+	tmpComment = null;
>+	Lexer.doc_state = XmlCommentState.Allowed;
>+	return s;
>+}
>+
> /* end end end */
> }
>Index: ChangeLog
>===================================================================
>--- ChangeLog	(revision 36885)
>+++ ChangeLog	(working copy)
>@@ -1,3 +1,35 @@
>+2004-11-30  Atsushi Enomoto  <atsushi at ximian.com>
>+
>+	all things are for /doc support:
>+
>+	* driver.cs:
>+	  Handle /doc command line option.
>+	  Report error 2006 instead of 5 for missing file name for /doc.
>+	  Added call to RootContext.GenerateDocComment() after type resolution.
>+	* cs-tokenizer.cs:
>+	  Added support for picking up documentation (/// and /** ... */),
>+	  including a new XmlCommentState enumeration.
>+	* cs-parser.jay:
>+	  Added lines to fill Documentation element for field, constant,
>+	  property, indexer, method, constructor, destructor, operator, event
>+	  and class, struct, interface, delegate, enum.
>+	  Added lines to warn incorrect comment.
>+	* rootcontext.cs :
>+	  Added NeedDocument, XmlCommentOutput and XmlDocumentation (values
>+	  are passed only when /doc was specified).
>+	  Added StoredDocuments() to cache <include>d xml comment documents.
>+	  Added static GenerateDocComment().
>+	* decl.cs:
>+	  Added DocComment, DocCommentHeader, GenerateDocComment() and
>+	  OnGenerateDocComment() and some supporting private members for
>+	  /doc feature to MemberCore.
>+	* class.cs:
>+	  Added GenerateDocComment() on TypeContainer, MethodCore and Operator.
>+	* delegate.cs:
>+	  Added overriden DocCommentHeader.
>+	* enum.cs:
>+	  Added overriden DocCommentHeader and GenerateDocComment().
>+
> 2004-11-30  Raja R Harinath  <rharinath at novell.com>
> 
> 	* Makefile (mcs.exe) [PROFILE=default]: Keep a copy of mcs.exe in
>Index: driver.cs
>===================================================================
>--- driver.cs	(revision 36885)
>+++ driver.cs	(working copy)
>@@ -17,6 +17,7 @@
> 	using System.IO;
> 	using System.Text;
> 	using System.Globalization;
>+	using System.Xml;
> 	using System.Diagnostics;
> 
> 	public enum Target {
>@@ -98,6 +99,11 @@
> 		static Encoding encoding;
> 
> 		//
>+		// XML Comment documentation
>+		//
>+		static string xml_documentation_file;
>+
>+		//
> 		// Whether the user has specified a different encoder manually
> 		//
> 		static bool using_default_encoder = true;
>@@ -220,6 +226,7 @@
> 				"   -nostdlib[+|-]     Does not load core libraries\n" +
> 				"   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
> 				"   -out:FNAME         Specifies output file\n" +
>+				"   -doc:XMLFILE         Generates xml documentation into specified file\n" +
> 				"   -pkg:P1[,Pn]       References packages P1..Pn\n" + 
> 				"   --expect-error X   Expect that error X will be encountered\n" +
> 				"   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
>@@ -1101,10 +1108,11 @@
> 			}
> 			case "/doc": {
> 				if (value == ""){
>-					Report.Error (5, arg + " requires an argument");
>+					Report.Error (2006, arg + " requires an argument");
> 					Environment.Exit (1);
> 				}
>-				// TODO handle the /doc argument to generate xml doc
>+				xml_documentation_file = value;
>+				RootContext.Documentation = new Documentation ();
> 				return true;
> 			}
> 			case "/lib": {
>@@ -1536,6 +1544,7 @@
> 			if (timestamps)
> 				ShowTime ("Resolving tree");
> 			RootContext.ResolveTree ();
>+
> 			if (Report.Errors > 0)
> 				return false;
> 			if (timestamps)
>@@ -1546,6 +1555,13 @@
> 			RootContext.PopulateTypes ();
> 			RootContext.DefineTypes ();
> 			
>+			if (RootContext.Documentation != null &&
>+				!RootContext.Documentation.OutputDocComment (
>+					RootContext.Tree.Types,
>+					output_file,
>+					xml_documentation_file))
>+				return false;
>+
> 			TypeManager.InitCodeHelpers ();
> 
> 			//
>@@ -1735,7 +1751,6 @@
> #endif
> 			return (Report.Errors == 0);
> 		}
>-
> 	}
> 
> 	//
>Index: enum.cs
>===================================================================
>--- enum.cs	(revision 36885)
>+++ enum.cs	(working copy)
>@@ -14,6 +14,7 @@
> using System.Reflection;
> using System.Reflection.Emit;
> using System.Globalization;
>+using System.Xml;
> 
> namespace Mono.CSharp {
> 
>@@ -100,13 +101,17 @@
> 		protected override void VerifyObsoleteAttribute()
> 		{
> 		}
>+
>+		public override string DocCommentHeader {
>+			get { return "F:"; }
>+		}
> 	}
> 
> 	/// <summary>
> 	///   Enumeration container
> 	/// </summary>
> 	public class Enum : DeclSpace {
>-		ArrayList ordered_enums;
>+		public ArrayList ordered_enums;
> 		
> 		public Expression BaseType;
> 		
>@@ -152,7 +157,7 @@
> 		///   Adds @name to the enumeration space, with @expr
> 		///   being its definition.  
> 		/// </summary>
>-		public void AddEnumMember (string name, Expression expr, Location loc, Attributes opt_attrs)
>+		public void AddEnumMember (string name, Expression expr, Location loc, Attributes opt_attrs, string documentation)
> 		{
> 			if (name == "value__") {
> 				Report.Error (76, loc, "An item in an enumeration can't have an identifier `value__'");
>@@ -160,6 +165,7 @@
> 			}
> 
> 			EnumMember em = new EnumMember (this, expr, name, loc, opt_attrs);
>+			em.DocComment = documentation;
> 			if (!AddToContainer (em, false, name, ""))
> 				return;
> 
>@@ -784,5 +790,21 @@
> 		{
> 			// UnderlyingType is never obsolete
> 		}
>+
>+		//
>+		// Generates xml doc comments (if any), and if required,
>+		// handle warning report.
>+		//
>+		internal override void GenerateDocComment (DeclSpace ds)
>+		{
>+			DocUtil.GenerateEnumDocComment (this, ds);
>+		}
>+
>+		//
>+		//   Represents header string for documentation comment.
>+		//
>+		public override string DocCommentHeader {
>+			get { return "T:"; }
>+		}
> 	}
> }
>Index: doc.cs
>===================================================================
>--- doc.cs	(revision 0)
>+++ doc.cs	(revision 0)
>@@ -0,0 +1,703 @@
>+//
>+// doc.cs: Support for XML documentation comment.
>+//
>+// Author:
>+//	Atsushi Enomoto <atsushi at ximian.com>
>+//
>+// Licensed under the terms of the GNU GPL
>+//
>+// (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
>+//
>+//
>+using System;
>+using System.Collections;
>+using System.IO;
>+using System.Reflection;
>+using System.Reflection.Emit;
>+using System.Runtime.CompilerServices;
>+using System.Runtime.InteropServices;
>+using System.Security;
>+using System.Security.Permissions;
>+using System.Text;
>+using System.Xml;
>+
>+using Mono.CompilerServices.SymbolWriter;
>+
>+namespace Mono.CSharp {
>+
>+	//
>+	// Support class for XML documentation.
>+	//
>+	public class DocUtil
>+	{
>+		// TypeContainer
>+
>+		//
>+		// Generates xml doc comments (if any), and if required,
>+		// handle warning report.
>+		//
>+		internal static void GenerateTypeDocComment (TypeContainer t,
>+			DeclSpace ds)
>+		{
>+			GenerateDocComment (t, ds);
>+
>+			if (t.default_static_constructor != null)
>+				t.default_static_constructor.GenerateDocComment (t);
>+
>+			if (t.InstanceConstructors != null)
>+				foreach (Constructor c in t.InstanceConstructors)
>+					c.GenerateDocComment (t);
>+
>+			if (t.Types != null)
>+				foreach (TypeContainer tc in t.Types)
>+					tc.GenerateDocComment (t);
>+
>+			if (t.Enums != null)
>+				foreach (Enum en in t.Enums)
>+					en.GenerateDocComment (t);
>+
>+			if (t.Constants != null)
>+				foreach (Const c in t.Constants)
>+					c.GenerateDocComment (t);
>+
>+			if (t.Fields != null)
>+				foreach (Field f in t.Fields)
>+					f.GenerateDocComment (t);
>+
>+			if (t.Events != null)
>+				foreach (Event e in t.Events)
>+					e.GenerateDocComment (t);
>+
>+			if (t.Indexers != null)
>+				foreach (Indexer ix in t.Indexers)
>+					ix.GenerateDocComment (t);
>+
>+			if (t.Properties != null)
>+				foreach (Property p in t.Properties)
>+					p.GenerateDocComment (t);
>+
>+			if (t.Methods != null)
>+				foreach (Method m in t.Methods)
>+					m.GenerateDocComment (t);
>+
>+			if (t.Operators != null)
>+				foreach (Operator o in t.Operators)
>+					o.GenerateDocComment (t);
>+		}
>+
>+		// MemberCore
>+
>+		private static XmlNode GetDocCommentNode (MemberCore mc,
>+			string name)
>+		{
>+			// FIXME: It could be even optimizable as not
>+			// to use XmlDocument. But anyways the nodes
>+			// are not kept in memory.
>+			XmlDocument doc = RootContext.Documentation.XmlDocumentation;
>+			try {
>+				XmlElement el = doc.CreateElement ("member");
>+				el.SetAttribute ("name", name);
>+				string normalized = mc.DocComment;
>+				el.InnerXml = normalized;
>+				// csc keeps lines as written in the sources
>+				// and inserts formatting indentation (which 
>+				// is different from XmlTextWriter.Formatting
>+				// one), but when a start tag contains an 
>+				// endline, it joins the next line. We don't
>+				// have to follow such a hacky behavior.
>+				string [] split =
>+					mc.DocComment.Split ('\n');
>+				int j = 0;
>+				for (int i = 0; i < split.Length; i++) {
>+					string s = split [i].TrimEnd ();
>+					if (s.Length > 0)
>+						split [j++] = s;
>+				}
>+				el.InnerXml = String.Join (
>+					"\n            ", split, 0, j);
>+				return el;
>+			} catch (XmlException ex) {
>+				Report.Warning (1570, 1, mc.Location, "XML comment on '{0}' has non-well-formed XML ({1}).", name, ex.Message);
>+				XmlComment com = doc.CreateComment (String.Format ("FIXME: Invalid documentation markup was found for member {0}", name));
>+				return com;
>+			}
>+		}
>+
>+		//
>+		// Generates xml doc comments (if any), and if required,
>+		// handle warning report.
>+		//
>+		internal static void GenerateDocComment (MemberCore mc,
>+			DeclSpace ds)
>+		{
>+			if (mc.DocComment != null) {
>+				string name = mc.GetDocCommentName (ds);
>+
>+				XmlNode n = GetDocCommentNode (mc, name);
>+
>+				XmlElement el = n as XmlElement;
>+				if (el != null) {
>+					mc.OnGenerateDocComment (ds, el);
>+
>+					// FIXME: it could be done with XmlReader
>+					foreach (XmlElement inc in n.SelectNodes (".//include"))
>+						HandleInclude (mc, inc);
>+
>+					// FIXME: it could be done with XmlReader
>+					DeclSpace dsTarget = mc as DeclSpace;
>+					if (dsTarget == null)
>+						dsTarget = ds;
>+
>+					foreach (XmlElement see in n.SelectNodes (".//see"))
>+						HandleSee (mc, dsTarget, name, see);
>+					foreach (XmlElement seealso in n.SelectNodes (".//seealso"))
>+						HandleSeeAlso (mc, dsTarget, name, seealso);
>+				}
>+
>+				n.WriteTo (RootContext.Documentation.XmlCommentOutput);
>+			}
>+			else if (mc.IsExposedFromAssembly (ds) &&
>+				// There are no warnings when the container also
>+				// misses documentations.
>+				(ds == null || ds.DocComment != null))
>+			{
>+				Report.Warning (1591, 4, mc.Location,
>+					"Missing XML comment for publicly visible type or member '{0}'", mc.GetSignatureForError ());
>+			}
>+		}
>+
>+		//
>+		// Processes "include" element. Check included file and
>+		// embed the document content inside this documentation node.
>+		//
>+		private static void HandleInclude (MemberCore mc, XmlElement el)
>+		{
>+			string file = el.GetAttribute ("file");
>+			string path = el.GetAttribute ("path");
>+			if (file == "") {
>+				Report.Warning (1590, 1, mc.Location, "Invalid XML 'include' element; Missing 'file' attribute.");
>+				el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Include tag is invalid "), el);
>+			}
>+			else if (path == "") {
>+				Report.Warning (1590, 1, mc.Location, "Invalid XML 'include' element; Missing 'path' attribute.");
>+				el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Include tag is invalid "), el);
>+			}
>+			else {
>+				XmlDocument doc = RootContext.Documentation.StoredDocuments [file] as XmlDocument;
>+				if (doc == null) {
>+					try {
>+						doc = new XmlDocument ();
>+						doc.Load (file);
>+						RootContext.Documentation.StoredDocuments.Add (file, doc);
>+					} catch (Exception) {
>+						el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (String.Format (" Badly formed XML in at comment file '{0}': cannot be included ", file)), el);
>+						Report.Warning (1592, 1, mc.Location, "Badly formed XML in included comments file -- '{0}'", file);
>+					}
>+				}
>+				bool keepIncludeNode = false;
>+				if (doc != null) {
>+					try {
>+						XmlNodeList nl = doc.SelectNodes (path);
>+						if (nl.Count == 0) {
>+							el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" No matching elements were found for the include tag embedded here. "), el);
>+					
>+							keepIncludeNode = true;
>+						}
>+						foreach (XmlNode n in nl)
>+							el.ParentNode.InsertBefore (el.OwnerDocument.ImportNode (n, true), el);
>+					} catch (Exception ex) {
>+						el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Failed to insert some or all of included XML "), el);
>+						Report.Warning (1589, 1, mc.Location, "Unable to include XML fragment '{0}' of file {1} -- {2}.", path, file, ex.Message);
>+					}
>+				}
>+				if (!keepIncludeNode)
>+					el.ParentNode.RemoveChild (el);
>+			}
>+		}
>+
>+		//
>+		// Handles <see> elements.
>+		//
>+		private static void HandleSee (MemberCore mc,
>+			DeclSpace ds, string name, XmlElement see)
>+		{
>+			HandleXrefCommon (mc, ds, name, see);
>+		}
>+
>+		//
>+		// Handles <seealso> elements.
>+		//
>+		private static void HandleSeeAlso (MemberCore mc,
>+			DeclSpace ds, string name, XmlElement seealso)
>+		{
>+			HandleXrefCommon (mc, ds, name, seealso);
>+		}
>+
>+		static readonly char [] wsChars =
>+			new char [] {' ', '\t', '\n', '\r'};
>+
>+		//
>+		// returns a full runtime type name from a name which might
>+		// be C# specific type name.
>+		//
>+		private static Type FindDocumentedType (MemberCore mc,
>+			string identifier, DeclSpace ds)
>+		{
>+			switch (identifier) {
>+			case "int":
>+				return typeof (int);
>+			case "uint":
>+				return typeof (uint);
>+			case "short":
>+				return typeof (short);
>+			case "ushort":
>+				return typeof (ushort);
>+			case "long":
>+				return typeof (long);
>+			case "ulong":
>+				return typeof (ulong);
>+			case "float":
>+				return typeof (float);
>+			case "double":
>+				return typeof (double);
>+			case "char":
>+				return typeof (char);
>+			case "decimal":
>+				return typeof (decimal);
>+			case "byte":
>+				return typeof (byte);
>+			case "sbyte":
>+				return typeof (sbyte);
>+			case "object":
>+				return typeof (object);
>+			case "bool":
>+				return typeof (bool);
>+			case "string":
>+				return typeof (string);
>+			case "void":
>+				return typeof (void);
>+			}
>+			return ds.FindType (mc.Location, identifier);
>+		}
>+
>+		//
>+		// Returns a MemberInfo that is referenced in XML documentation
>+		// (by "see" or "seealso" elements).
>+		//
>+		private static MemberInfo FindDocumentedMember (MemberCore mc,
>+			Type type, string memberName, Type [] paramList, 
>+			DeclSpace ds, out int warningType, string cref)
>+		{
>+			warningType = 0;
>+			MethodSignature msig = new MethodSignature (memberName, null, paramList);
>+			MemberInfo [] mis = type.FindMembers (
>+				MemberTypes.All,
>+				BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance,
>+				MethodSignature.method_signature_filter,
>+				msig);
>+			if (mis.Length > 0)
>+				return mis [0];
>+
>+			if (paramList.Length == 0) {
>+				// search for fields/events etc.
>+				mis = type.FindMembers (
>+					MemberTypes.All,
>+					BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance,
>+					Type.FilterName,
>+					memberName);
>+				return (mis.Length > 0) ? mis [0] : null;
>+			}
>+
>+			// search for operators (whose parameters exactly
>+			// matches with the list) and possibly report CS1581.
>+			string oper = null;
>+			string returnTypeName = null;
>+			if (memberName.StartsWith ("implicit operator ")) {
>+				oper = "op_Implicit";
>+				returnTypeName = memberName.Substring (18).Trim (wsChars);
>+			}
>+			else if (memberName.StartsWith ("explicit operator ")) {
>+				oper = "op_Explicit";
>+				returnTypeName = memberName.Substring (18).Trim (wsChars);
>+			}
>+			else if (memberName.StartsWith ("operator ")) {
>+				oper = memberName.Substring (9).Trim (wsChars);
>+				switch (oper) {
>+				// either unary or binary
>+				case "+":
>+					oper = paramList.Length == 2 ?
>+						Binary.oper_names [(int) Binary.Operator.Addition] :
>+						Unary.oper_names [(int) Unary.Operator.UnaryPlus];
>+					break;
>+				case "-":
>+					oper = paramList.Length == 2 ?
>+						Binary.oper_names [(int) Binary.Operator.Subtraction] :
>+						Unary.oper_names [(int) Unary.Operator.UnaryNegation];
>+					break;
>+				// unary
>+				case "!":
>+					oper = Unary.oper_names [(int) Unary.Operator.LogicalNot]; break;
>+				case "~":
>+					oper = Unary.oper_names [(int) Unary.Operator.OnesComplement]; break;
>+					
>+				case "++":
>+					oper = "op_Increment"; break;
>+				case "--":
>+					oper = "op_Decrement"; break;
>+				case "true":
>+					oper = "op_True"; break;
>+				case "false":
>+					oper = "op_False"; break;
>+				// binary
>+				case "*":
>+					oper = Binary.oper_names [(int) Binary.Operator.Multiply]; break;
>+				case "/":
>+					oper = Binary.oper_names [(int) Binary.Operator.Division]; break;
>+				case "%":
>+					oper = Binary.oper_names [(int) Binary.Operator.Modulus]; break;
>+				case "&":
>+					oper = Binary.oper_names [(int) Binary.Operator.BitwiseAnd]; break;
>+				case "|":
>+					oper = Binary.oper_names [(int) Binary.Operator.BitwiseOr]; break;
>+				case "^":
>+					oper = Binary.oper_names [(int) Binary.Operator.ExclusiveOr]; break;
>+				case "<<":
>+					oper = Binary.oper_names [(int) Binary.Operator.LeftShift]; break;
>+				case ">>":
>+					oper = Binary.oper_names [(int) Binary.Operator.RightShift]; break;
>+				case "==":
>+					oper = Binary.oper_names [(int) Binary.Operator.Equality]; break;
>+				case "!=":
>+					oper = Binary.oper_names [(int) Binary.Operator.Inequality]; break;
>+				case "<":
>+					oper = Binary.oper_names [(int) Binary.Operator.LessThan]; break;
>+				case ">":
>+					oper = Binary.oper_names [(int) Binary.Operator.GreaterThan]; break;
>+				case "<=":
>+					oper = Binary.oper_names [(int) Binary.Operator.LessThanOrEqual]; break;
>+				case ">=":
>+					oper = Binary.oper_names [(int) Binary.Operator.GreaterThanOrEqual]; break;
>+				default:
>+					warningType = 1584;
>+					Report.Warning (1020, 1, mc.Location, "Overloadable {0} operator is expected", paramList.Length == 2 ? "binary" : "unary");
>+					Report.Warning (1584, 1, mc.Location, "XML comment on '{0}' has syntactically incorrect attribute '{1}'", mc.GetSignatureForError (), cref);
>+					return null;
>+				}
>+			}
>+			// here we still does not consider return type (to
>+			// detect CS1581 or CS1002+CS1584).
>+			msig = new MethodSignature (oper, null, paramList);
>+			mis = type.FindMembers (
>+				MemberTypes.Method,
>+				BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static,
>+				MethodSignature.method_signature_filter,
>+				msig);
>+			if (mis.Length == 0)
>+				return null; // CS1574
>+			MemberInfo mi = mis [0];
>+			Type expected = mi is MethodInfo ?
>+				((MethodInfo) mi).ReturnType :
>+				mi is PropertyInfo ?
>+				((PropertyInfo) mi).PropertyType :
>+				null;
>+			if (returnTypeName != null) {
>+				Type returnType = FindDocumentedType (mc, returnTypeName, ds);
>+				if (returnType == null || returnType != expected) {
>+					warningType = 1581;
>+					Report.Warning (1581, 1, mc.Location, "Invalid return type in XML comment cref attribute '{0}'", cref);
>+					return null;
>+				}
>+			}
>+			return mis [0];
>+		}
>+
>+		private static Type [] emptyParamList = new Type [0];
>+
>+		//
>+		// Processes "see" or "seealso" elements.
>+		// Checks cref attribute.
>+		//
>+		private static void HandleXrefCommon (MemberCore mc,
>+			DeclSpace ds, string name, XmlElement xref)
>+		{
>+			string cref = xref.GetAttribute ("cref").Trim (wsChars);
>+			// when, XmlReader, "if (cref == null)"
>+			if (!xref.HasAttribute ("cref"))
>+				return;
>+			if (cref.Length == 0)
>+				Report.Warning (1001, 1, mc.Location, "Identifier expected");
>+				// ... and continue until CS1584.
>+
>+			string signature, identifier, parameters;
>+
>+			// strip 'T:' 'M:' 'F:' 'P:' 'E:' etc.
>+			// Here, MS ignores its member kind. No idea why.
>+			if (cref.Length > 2 && cref [1] == ':')
>+				signature = cref.Substring (2).Trim (wsChars);
>+			else
>+				signature = cref;
>+
>+			int parensPos = signature.IndexOf ('(');
>+			if (parensPos > 0 && signature [signature.Length - 1] == ')') {
>+				identifier = signature.Substring (0, parensPos).Trim (wsChars);
>+				parameters = signature.Substring (parensPos + 1, signature.Length - parensPos - 2);
>+			}
>+			else {
>+				identifier = signature;
>+				parameters = String.Empty;
>+			}
>+
>+			string alias = ds.LookupAlias (identifier);
>+			if (alias != null)
>+				identifier = alias;
>+
>+			// Check if identifier is valid.
>+			// This check is not necessary to mark as error, but
>+			// csc specially reports CS1584 for wrong identifiers.
>+			foreach (string nameElem in identifier.Split ('.')) {
>+				if (!Tokenizer.IsValidIdentifier (nameElem) && nameElem.IndexOf ("operator") < 0) {
>+					Report.Warning (1584, 1, mc.Location, "XML comment on '{0}' has syntactically incorrect attribute '{1}'", mc.GetSignatureForError (), cref);
>+					xref.SetAttribute ("cref", "!:" + signature);
>+					return;
>+				}
>+			}
>+
>+			// check if parameters are valid
>+			Type [] parameterTypes = emptyParamList;
>+			if (parameters.Length > 0) {
>+				string [] paramList = parameters.Split (',');
>+				ArrayList plist = new ArrayList ();
>+				for (int i = 0; i < paramList.Length; i++) {
>+					string paramTypeName = paramList [i].Trim (wsChars);
>+					alias = ds.LookupAlias (paramTypeName);
>+					if (alias != null)
>+						paramTypeName = alias;
>+					Type paramType = FindDocumentedType (mc, paramTypeName, ds);
>+					if (paramType == null) {
>+						Report.Warning (1580, 1, mc.Location, "Invalid type for parameter '{0}' in XML comment cref attribute '{1}'", i + 1, cref);
>+						return;
>+					}
>+					plist.Add (paramType);
>+				}
>+				parameterTypes = plist.ToArray (typeof (Type)) as Type [];
>+			}
>+
>+			Type type = FindDocumentedType (mc, identifier, ds);
>+			if (type != null) {
>+				xref.SetAttribute ("cref", "T:" + type.FullName.Replace ("+", "."));
>+				return; // a type
>+			}
>+
>+			int period = identifier.LastIndexOf ('.');
>+			if (period > 0) {
>+				string typeName = identifier.Substring (0, period);
>+				string memberName = identifier.Substring (period + 1);
>+				type = FindDocumentedType (mc, typeName, ds);
>+				int warnResult;
>+				if (type != null) {
>+					MemberInfo mi = FindDocumentedMember (mc, type, memberName, parameterTypes, ds, out warnResult, cref);
>+					if (warnResult > 0)
>+						return;
>+					if (mi != null) {
>+						xref.SetAttribute ("cref", GetMemberDocHead (mi.MemberType) + type.FullName.Replace ("+", ".") + "." + memberName);
>+						return; // a member of a type
>+					}
>+				}
>+			}
>+			else {
>+				int warnResult;
>+				MemberInfo mi = FindDocumentedMember (mc, ds.TypeBuilder, identifier, parameterTypes, ds, out warnResult, cref);
>+				if (warnResult > 0)
>+					return;
>+				if (mi != null) {
>+					xref.SetAttribute ("cref", GetMemberDocHead (mi.MemberType) + ds.TypeBuilder.FullName.Replace ("+", ".") + "." + identifier);
>+					return; // local member name
>+				}
>+			}
>+
>+			Report.Warning (1574, 1, mc.Location, "XML comment on '{0}' has cref attribute '{1}' that could not be resolved in '{2}'.", mc.GetSignatureForError (), cref, ds.GetSignatureForError ());
>+
>+			xref.SetAttribute ("cref", "!:" + identifier);
>+		}
>+
>+		//
>+		// Get a prefix from member type for XML documentation (used
>+		// to formalize cref target name).
>+		//
>+		static string GetMemberDocHead (MemberTypes type)
>+		{
>+			switch (type) {
>+			case MemberTypes.Constructor:
>+			case MemberTypes.Method:
>+				return "M:";
>+			case MemberTypes.Event:
>+				return "E:";
>+			case MemberTypes.Field:
>+				return "F:";
>+			case MemberTypes.NestedType:
>+			case MemberTypes.TypeInfo:
>+				return "T:";
>+			case MemberTypes.Property:
>+				return "P:";
>+			}
>+			return "!:";
>+		}
>+
>+		// MethodCore
>+
>+		//
>+		// Returns a string that represents the signature for this 
>+		// member which should be used in XML documentation.
>+		//
>+		public static string GetMethodDocCommentName (MethodCore mc, DeclSpace ds)
>+		{
>+			Parameter [] plist = mc.Parameters.FixedParameters;
>+			Parameter parr = mc.Parameters.ArrayParameter;
>+			string paramSpec = String.Empty;
>+			if (plist != null) {
>+				StringBuilder psb = new StringBuilder ();
>+				foreach (Parameter p in plist) {
>+					psb.Append (psb.Length != 0 ? "," : "(");
>+					psb.Append (p.ParameterType.FullName.Replace ("+", "."));
>+				}
>+				psb.Append (")");
>+				paramSpec = psb.ToString ();
>+			}
>+			else if (parr != null)
>+				paramSpec = String.Concat (
>+					"(",
>+					parr.ParameterType.FullName.Replace ("+", "."),
>+					")");
>+
>+			string name = mc is Constructor ? "#ctor" : mc.Name;
>+			return String.Concat (mc.DocCommentHeader, ds.Name, ".", name, paramSpec);
>+		}
>+
>+		//
>+		// Raised (and passed an XmlElement that contains the comment)
>+		// when GenerateDocComment is writing documentation expectedly.
>+		//
>+		// FIXME: with a few effort, it could be done with XmlReader,
>+		// that means removal of DOM use.
>+		//
>+		internal static void OnMethodGenerateDocComment (
>+			MethodCore mc, DeclSpace ds, XmlElement el)
>+		{
>+			Hashtable paramTags = new Hashtable ();
>+			foreach (XmlElement pelem in el.SelectNodes ("param")) {
>+				int i;
>+				string xname = pelem.GetAttribute ("name");
>+				if (xname == "")
>+					continue; // really? but MS looks doing so
>+				if (xname != "" && mc.Parameters.GetParameterByName (xname, out i) == null)
>+					Report.Warning (1572, 2, mc.Location, "XML comment on '{0}' has a 'param' tag for '{1}', but there is no such parameter.", mc.Name, xname);
>+				else if (paramTags [xname] != null)
>+					Report.Warning (1571, 2, mc.Location, "XML comment on '{0}' has a duplicate param tag for '{1}'", mc.Name, xname);
>+				paramTags [xname] = xname;
>+			}
>+			Parameter [] plist = mc.Parameters.FixedParameters;
>+			Parameter parr = mc.Parameters.ArrayParameter;
>+			if (plist != null) {
>+				foreach (Parameter p in plist) {
>+					if (paramTags.Count > 0 && paramTags [p.Name] == null)
>+						Report.Warning (1573, 4, mc.Location, "Parameter '{0}' has no matching param tag in the XML comment for '{1}' (but other parameters do)", mc.Name, p.Name);
>+				}
>+			}
>+		}
>+
>+		// Enum
>+		public static void GenerateEnumDocComment (Enum e, DeclSpace ds)
>+		{
>+			GenerateDocComment (e, ds);
>+			foreach (string name in e.ordered_enums) {
>+				MemberCore mc = e.GetDefinition (name);
>+				GenerateDocComment (mc, e);
>+			}
>+		}
>+	}
>+
>+	//
>+	// Implements XML documentation generation.
>+	//
>+	public class Documentation
>+	{
>+		public Documentation ()
>+		{
>+			XmlDocumentation = new XmlDocument ();
>+			XmlDocumentation.PreserveWhitespace = false;
>+		}
>+
>+		//
>+		// Used to create element which helps well-formedness checking.
>+		//
>+		public XmlDocument XmlDocumentation;
>+
>+		//
>+		// The output for XML documentation.
>+		//
>+		public XmlWriter XmlCommentOutput;
>+
>+		//
>+		// Stores XmlDocuments that are included in XML documentation.
>+		//
>+		public Hashtable StoredDocuments = new Hashtable ();
>+
>+		//
>+		// Outputs XML documentation comment from tokenized comments.
>+		//
>+		public bool OutputDocComment (
>+			TypeContainer root,
>+			string asmfilename,
>+			string docfilename)
>+		{
>+			XmlTextWriter w = null;
>+			try {
>+				w = new XmlTextWriter (docfilename, null);
>+				w.Indentation = 4;
>+				w.Formatting = Formatting.Indented;
>+				w.WriteStartDocument ();
>+				w.WriteStartElement ("doc");
>+				w.WriteStartElement ("assembly");
>+				w.WriteStartElement ("name");
>+				w.WriteString (Path.ChangeExtension (asmfilename, null));
>+				w.WriteEndElement (); // name
>+				w.WriteEndElement (); // assembly
>+				w.WriteStartElement ("members");
>+				XmlCommentOutput = w;
>+				GenerateDocComment (root);
>+				w.WriteFullEndElement (); // members
>+				w.WriteEndElement ();
>+				w.WriteWhitespace (Environment.NewLine);
>+				w.WriteEndDocument ();
>+				return true;
>+			} catch (Exception ex) {
>+				Report.Error (1569, "Error generating XML documentation file '{0}' ('{1}')", docfilename, ex.Message);
>+				return false;
>+			} finally {
>+				if (w != null)
>+					w.Close ();
>+			}
>+		}
>+
>+		//
>+		// Fixes full type name of each documented types/members up.
>+		//
>+		public void GenerateDocComment (TypeContainer root)
>+		{
>+			if (root.Interfaces != null)
>+				foreach (Interface i in root.Interfaces) 
>+					DocUtil.GenerateTypeDocComment (i, null);
>+
>+			foreach (TypeContainer tc in root.Types)
>+				DocUtil.GenerateTypeDocComment (tc, null);
>+
>+			if (root.Delegates != null)
>+				foreach (Delegate d in root.Delegates) 
>+					DocUtil.GenerateDocComment (d, null);
>+
>+			if (root.Enums != null)
>+				foreach (Enum e in root.Enums)
>+					DocUtil.GenerateEnumDocComment (e, null);
>+		}
>+	}
>+}
>
>Property changes on: doc.cs
>___________________________________________________________________
>Name: svn:executable
>   + *
>
>  
>




More information about the Mono-devel-list mailing list