**** Merged r36954 from MCS ****
authorMartin Baulig <martin@novell.com>
Sat, 4 Dec 2004 23:29:44 +0000 (23:29 -0000)
committerMartin Baulig <martin@novell.com>
Sat, 4 Dec 2004 23:29:44 +0000 (23:29 -0000)
svn path=/trunk/mcs/; revision=37121

1  2 
mcs/gmcs/ChangeLog
mcs/gmcs/class.cs
mcs/gmcs/cs-parser.jay
mcs/gmcs/cs-tokenizer.cs
mcs/gmcs/decl.cs
mcs/gmcs/delegate.cs
mcs/gmcs/doc.cs
mcs/gmcs/driver.cs
mcs/gmcs/enum.cs
mcs/gmcs/rootcontext.cs

index 845a6b9c83b96be6f3f8caf143887ff7b4a66287,f3e57f1dda65168d79f1bc78c7bc2dd70f9911c2..27ffd82bf347ebd7a3b4ce200ee3130fa294ba07
++2004-12-02  Atsushi Enomoto  <atsushi@ximian.com>
++
++      all things are for /doc support:
++
++      * doc.cs: new file that supports XML documentation generation.
++      * mcs.exe.sources: added doc.cs.
++      * driver.cs:
++        Handle /doc command line option.
++        Report error 2006 instead of 5 for missing file name for /doc.
++        Generate XML documentation when required, 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 Documentation field (passed only when /doc was specified).
++      * 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-12-01  Miguel de Icaza  <miguel@ximian.com>
 +
 +      * cfold.cs (ConstantFold.DoConstantNumericPromotions): After
 +      unwrapping the enumeration values, chain to
 +      DoConstantNumericPromotions again, so we can promote things to the
 +      fundamental types (takes care of enums that are bytes, sbytes).
 +
 +      Fixes bug #62054.
 +
 +2004-12-01  Raja R Harinath  <rharinath@novell.com>
 +
 +      * attribute.cs (Attribute.CheckAttributeType): Remove complain flag.
 +      Fix long-standing bug in type-lookup.  Use FindType instead of
 +      LookupType when ec.ResolvingTypeTree.
 +      (Attribute.ResolveType, Attribute.Resolve)
 +      (Attribute.DefinePInvokeMethod,GlobalAttribute.CheckAttributeType):
 +      Update to changes.
 +      (Attributes.Search): Remove internal version.  Update.
 +      (Attributes.SearchMulti): Update.
 +      (Attributes.GetClsCompliantAttribute): Remove.
 +      (Attributes.GetIndexerNameAttribute): Remove.
 +      * decl.cs (MemberCore.GetClsCompliantAttributeValue): Update to changes.
 +      (DeclSpace.GetClsCompliantAttributeValue): Likewise.
 +      * class.cs (Indexer.Define): Likewise.
 +
 +2004-12-01  Marek Safar  <marek.safar@seznam.cz>
 +
 +      Fix bug #68790
 +      * ecore.cs: CheckMarshallByRefAccess new virtual method for testing
 +      MarshallByReference members access.
 +
 +      * expression.cs: Use CheckMarshallByRefAccess;
 +      Better error CS0197 message.
 +
 +      * report.cs: Print whole related error message.
 +
 +2004-11-29  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * class (GetClassBases): Better error 60 report.
 +      (EventProperty): Disabled warning 67 detection.
 +
 +2004-11-29  Marek Safar  <marek.safar@seznam.cz>
 +
 +      Fix bug #60324
 +      * cfold.cs (Assign.DoResolve): Add subtraction for DecimalConstant.
 +
 +      * constant.cs (DecimalConstant.Emit): Don't use int ctor for
 +      precise values.
 +
 +2004-11-29  Marek Safar  <marek.safar@seznam.cz>
 +
 +      Fix bug #49488
 +      * assign.cs (Assign.DoResolve): Add error 1648, 1650 report.
 +
 +      * decl.cs (MemberCore.MemberName): Error 1648 in compiler.
 +
 +2004-11-26  Miguel de Icaza  <miguel@ximian.com>
 +
 +      * attribute.cs (Attribute.Resolve): Refine error reporting and
 +      report a cs0117 if the identifier does not exist, to distinguish
 +      from 0617 which is a miss-use of the actual identifier.
 +
 +      * ecore.cs (EventExpr.Emit): Refine error report and distinguish
 +      between cs0070 and cs0079.
 +
 +      * class.cs (MemberBase.DoDefine): When reporting a wrong
 +      accessibility level, we use MethodCore to compare instead of
 +      Method (this was a regression in some refactoring effort).
 +
 +      So now we correctly report cs0056 again.
 +
 +      * convert.cs (ImplicitReferenceConversion): Corrected typo, I was
 +      testing the target_type (which was known to be object_type) and
 +      not the source type (which is anonymous_method).
 +
 +      Fixed reporting of error cs1660.
 +
 +      * expression.cs (UserCast.Source): Expose the underlying cast.
 +
 +      * statement.cs (Switch.SwitchGoverningType): Sort the list of
 +      allowed types to find a match to int32 first (most common).
 +
 +      In addition, it ignores any ImplicitUserConversions that did an
 +      internal implicit conversion (as the switch statement allows only
 +      one integral conversion to exist).
 +
 +      * class.cs (PartialContainer.Create): rename `name' to
 +      `member_name' for clarity.  Then replace the string calls with a
 +      call to MemberName.GetPartialName, as now using
 +      MemberName.ToString is an error (this is due to the side effects
 +      it had, that were fixed in the past).
 +
 +      This will restore the error reporting on a number of partial class
 +      errors that were missusing this (and getting an exception as a
 +      results, which is now just a plain textual warning, because
 +      yyparse debug output would crash otherwise).
 +
 +2004-11-26  Raja R Harinath  <rharinath@novell.com>
 +
 +      * Makefile (PROGRAM_INSTALL_DIR): Remove.
 +
 +2004-11-25  Ben Maurer  <bmaurer@ximian.com>
 +
 +      * rootcontext.cs (LookupType): Make sure to cache lookups that
 +      don't give us a negative result. This saves about 5% of corlib
 +      compilation time.
 +
 +2004-11-25  Miguel de Icaza  <miguel@ximian.com>
 +
 +      * report.cs (AbstractMessage.Print): messages are sent to stderr
 +
 +      * class.cs (TypeContainer.GetClassBases): It is an error to have a
 +      non-interface in the list of interfaces (at this point, either
 +      parent was properly set, or a base class is being listed in the
 +      interfaces section).
 +
 +      This flags error 1722, and resolves the crash from bug 69259.
 +
 +2004-11-25  Ben Maurer  <bmaurer@ximian.com>
 +
 +      * statement.cs (Using.EmitExpressionFinally): make this work right
 +      for valuetypes. Fixes 69926.
 +
 +2004-11-25  Miguel de Icaza  <miguel@ximian.com>
 +
 +      * const.cs (Const.ChangeType): Cope with the "0 literal can be
 +      converted to an enum" here, before we try to change the underlying
 +      type.  This code exists, but it is a different code path than the
 +      one used while encoding constants.
 +
 +      (ImplicitReferenceConversionExists): In addition, resynchronized
 +      the code here, so it matches the same code in
 +      ImplicitReferenceConversionExists for the `from any class-type S
 +      to any interface-type T'.       
 +
 +2004-11-25  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * cfold.cs (BinaryFold): Add addition for DecimalConstant.
 +
 +2004-11-24  Miguel de Icaza  <miguel@ximian.com>
 +
 +      * cs-parser.jay: Use verbosity accordingly. 
 +
 +2004-11-24  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * expression.cs (Unary.ResolveOperator): Do not report warning;
 +      AddressOf reads from variable.
 +      
 +      (LocalVariableReferences.DoResolveBase): Improved my previous fix.
 +
 +2004-11-24  Marek Safar  <marek.safar@seznam.cz>
 +
 +      Fix bug #69462
 +
 +      * attribute.cs (Attributable): Removed CheckTargets.
 +      (Attributes.Emit): Explicit attribute targets are tested here.
 +
 +      * class.cs (EventField.ValidAttributeTargets): Explicit target "field" is
 +      not enabled for interfaces.
 +
 +      * codegen.cs (CommonAssemblyModulClass.AddAttributes): Removed CheckTargets.
 +      (GetAssemblyName): Ouch next bug there.
 +
 +2004-11-23  Carlos Alberto Cortez <calberto.cortez@gmail.com>
 +
 +      * expression.cs: Error 275 added.
 +      
 +2004-11-23  Marek Safar  <marek.safar@seznam.cz>
 +
 +      Fix bug #69177 (Implemented decimal constant support)
 +
 +      * cfold.cs (DoConstantNumericPromotions: Add DecimalConstant.
 +      (BinaryFold): Add DecimalConstant.
 +
 +      * const.cs (Define): Decimal constant 
 +      (is not constant.
 +      (ChangeType): Add decimal type handling.
 +      (LookupConstantValue): Don't set value for decimal type but
 +      emit DecimalConstantAttribute. Needed for constant optimization.
 +
 +      * constant.cs (ToDecimal): New method.
 +      (ConvertToDecimal): New method.
 +      (IntConstant): Implemented ConvertToDecimal.
 +      (DecimalConstant.Emit): Emit optimized version for decimals in
 +      int range.
 +
 +      * expression.cs (ResolveOperator): Changed order of constant
 +      reduction to work correctly with native types which have
 +      overloaded operators.
 +      (ResolveMemberAccess): Extract constant value from attribute
 +      for decimal type.
 +
 +      * rootcontext.cs (ResolveCore): Add DecimalConstantAttribute.
 +
 +      * typemanager.cs (TypeManager): Add decimal_constant_attribute_type,
 +      void_decimal_ctor_int_arg, decimal_constant_attribute_ctor.
 +      (ChangeType): Decimal is special.
 +      (TypeToCoreType): Add decimal type.
 +
 +2004-11-22  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * convert.cs (ImplicitConversionRequired): Add error cs0642 for
 +      decimal types.
 +
 +2004-11-22  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * class.cs (EventField.ApplyAttributeBuilder): Fix error
 +      test cs1667-5.cs.
 +
 +2004-11-19  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * class.cs (MemberBase.DoDefine): Fix error cs0508 report.
 +
 +      * pending.cs (PendingImplementation): Grab only interfaces.
 +
 +2004-11-19  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * statement.cs (ForeachHelperMethods): Add location member and
 +      error 202 detection.
 +
 +2004-11-18  Marek Safar  <marek.safar@seznam.cz>
 +
 +      * expression.cs (DoResolveBase): Fixed wrong warning for out
 +      variables.
 +
 +2004-12-04  Martin Baulig  <martin@ximian.com>
 +
 +      * convert.cs (Convert.TypeParameter_to_Null): Use the constraints
 +      to check whether the conversion is ok.
 +
 +      * typemanager.cs (TypeManager.GetTypeArguments): Just return
 +      `Type.EmptyTypes' if we're not a generic TypeContainer.
 +
 +2004-11-25  Miguel de Icaza  <miguel@ximian.com>
 +
 +      * convert.cs (ImplicitReferenceConversionExists): A surprisingly
 +      old bug: when converting from the null literal to a pointer,
 +      return an EmptyCast, not the NullLiteral.
 +
 +      This fixes #69921, the recent null_type changes probably made this
 +      bug more prominent.
 +
 +2004-12-03  Martin Baulig  <martin@ximian.com>
 +
 +      * delegate.cs (NewDelegate.DoResolve): If we have an anonymous
 +      method as our child, call AnonymousMethod.Compatible() on it.
 +
 +2004-12-02  Miguel de Icaza  <miguel@ximian.com>
 +
 +      * class.cs (FieldBase): Use an unused bit field from the field to
 +      encode the `has_offset' property from the FieldMember.  This saves
 +      a couple of Ks on bootstrap compilation.
 +
 +      * delegate.cs (NewDelegate.DoResolve): If we have an anonymous
 +      method as our child, return the AnonymousMethod resolved
 +      expression.
 +
 +      * expression.cs (New.DoResolve): Allow return values from
 +      NewDelegate to also include AnonymousMethods.
 +
 +      Fixes #70150.
 +
  2004-11-29  Raja R Harinath  <rharinath@novell.com>
  
        * decl.cs (MemberCore.MemberName): Remove readonly to fix an error
index 67660ccac63a55ca73e2f22e60be0892fef5df29,2fb89414dde196f1cf5fe1367bb19a53f3757255..4cb48f00c403065baad05528dc6af8250c7f74af
@@@ -8,6 -8,6 +8,7 @@@
  // Licensed under the terms of the GNU GPL
  //
  // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
++// (C) 2004 Novell, Inc
  //
  //
  //  2002-10-11  Miguel de Icaza  <miguel@ximian.com>
@@@ -40,6 -40,6 +41,7 @@@ using System.Runtime.CompilerServices
  using System.Runtime.InteropServices;
  using System.Security;
  using System.Security.Permissions;
++using System.Xml;
  
  using Mono.CompilerServices.SymbolWriter;
  
@@@ -2395,6 -2397,6 +2397,10 @@@ namespace Mono.CSharp 
                        }
                }
  
++              public Constructor DefaultStaticConstructor {
++                      get { return default_static_constructor; }
++              }
++
                protected override bool VerifyClsCompliance (DeclSpace ds)
                {
                        if (!base.VerifyClsCompliance (ds))
                                return FindMembers (mt, new_bf, 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;
                        return false;
                }
  
++              //
++              // 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 ();
  
                        base.Emit ();
                }
++
++              //
++              //   Represents header string for documentation comment.
++              //
++              public override string DocCommentHeader {
++                      get { return "F:"; }
++              }
        }
  
        //
                        }
                }
  
++              //
++              //   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()
                {
                }
                                return attribute_targets;
                        }
                }
++
++              //
++              //   Represents header string for documentation comment.
++              //
++              public override string DocCommentHeader {
++                      get { return "P:"; }
++              }
        }
                        
        public class Property : PropertyBase, IIteratorContainer {
  
                        return TypeManager.GetFullNameSignature (EventBuilder);
                }
++
++              //
++              //   Represents header string for documentation comment.
++              //
++              public override string DocCommentHeader {
++                      get { return "E:"; }
++              }
        }
  
   
index 593c80731bd199b36564bb0750067c24d8a46391,811bb3100f24c35c2a75c31f26c19762d5296b57..a80460d34d3d0b888245621d2e8584cccccaa62d
@@@ -8,6 -8,6 +8,7 @@@
  // Licensed under the terms of the GNU GPL
  //
  // (C) 2001 Ximian, Inc (http://www.ximian.com)
++// (C) 2004 Novell, Inc
  //
  // TODO:
  //   (1) Figure out why error productions dont work.  `type-declaration' is a
@@@ -83,6 -83,6 +84,14 @@@ namespace Mono.CShar
                /// 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
@@@ -290,7 -290,7 +299,13 @@@ compilation_uni
        
  opt_EOF
        : /* empty */
++      {
++              Lexer.check_incorrect_doc_comment ();
++      }
        | EOF
++      {
++              Lexer.check_incorrect_doc_comment ();
++      }
        ;
  
  outer_declarations
@@@ -310,7 -310,7 +325,15 @@@ using_directive
  
  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
@@@ -386,6 -386,6 +409,10 @@@ namespace_nam
  
  namespace_body
        : OPEN_BRACE
++        {
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.Allowed;
++        }
          opt_using_directives
          opt_namespace_member_declarations
          CLOSE_BRACE
@@@ -502,6 -502,6 +529,13 @@@ attribute_section
                        } else {
                                $$ = new Attributes (sect);
                        }
++                      if ($$ == null) {
++                              if (RootContext.Documentation != null) {
++                                      Lexer.check_incorrect_doc_comment ();
++                                      Lexer.doc_state =
++                                              XmlCommentState.Allowed;
++                              }
++                      }
                } else {
                        $$ = new Attributes (sect);
                }               
@@@ -769,9 -769,9 +803,16 @@@ struct_declaratio
  
                current_class.SetParameterInfo ((ArrayList) $8);
  
++              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;
        ;
  
  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
@@@ -837,6 -837,6 +883,10 @@@ constant_declaratio
                                (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);
                }
          }
@@@ -889,6 -889,6 +939,10 @@@ field_declaratio
                                                 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);
                }
          }
@@@ -950,6 -950,6 +1004,8 @@@ variable_initialize
  method_declaration
        : method_header {
                iterator_container = (IIteratorContainer) $1;
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.NotAllowed;
          }
          method_body
          {
  
                current_local_parameters = null;
                iterator_container = null;
++
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.Allowed;
          }
        ;
  
@@@ -1031,6 -1031,6 +1090,9 @@@ method_heade
  
                current_local_parameters = (Parameters) $6;
  
++              if (RootContext.Documentation != null)
++                      method.DocComment = Lexer.consume_doc_comment ();
++
                $$ = method;
          }
        | opt_attributes
                                     lexer.Location);
  
                current_local_parameters = (Parameters) $6;
++
++              if (RootContext.Documentation != null)
++                      method.DocComment = Lexer.consume_doc_comment ();
++
                $$ = method;
          }
        | opt_attributes
                                            lexer.Location);
  
                current_local_parameters = (Parameters) $6;
++
++              if (RootContext.Documentation != null)
++                      method.DocComment = Lexer.consume_doc_comment ();
++
                $$ = method;
          }
        ;
@@@ -1214,7 -1214,7 +1284,12 @@@ parameter_arra
  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;
          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;
  
                if (name.TypeArguments != null)
                current_container.AddProperty (prop);
                implicit_value_parameter_type = null;
                iterator_container = null;
++
++              if (RootContext.Documentation != null)
++                      prop.DocComment = ConsumeStoredComment ();
++
          }
        ;
  
@@@ -1290,6 -1290,6 +1369,10 @@@ get_accessor_declaratio
                $$ = 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;
          }
        ;
  
@@@ -1327,6 -1327,6 +1410,10 @@@ set_accessor_declaratio
                $$ = 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;
          }
        ;
  
@@@ -1372,10 -1372,10 +1459,20 @@@ interface_declaratio
  
                current_class.SetParameterInfo ((ArrayList) $8);
  
++              if (RootContext.Documentation != null) {
++                      current_class.DocComment = Lexer.consume_doc_comment ();
++                      Lexer.doc_state = XmlCommentState.Allowed;
++              }
++
                current_class.Register ();
          }
          interface_body opt_semicolon
          { 
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.Allowed;
++        }
++        opt_semicolon 
++        {
                $$ = current_class;
  
                current_container = current_container.Parent;
@@@ -1408,25 -1408,25 +1505,37 @@@ interface_member_declaratio
                Method m = (Method) $1;
  
                current_container.AddMethod (m);
++
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.Allowed;
          }
        | interface_property_declaration        
          { 
                Property p = (Property) $1;
  
                current_container.AddProperty (p);
--          }
++
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.Allowed;
++        }
        | interface_event_declaration 
            { 
                if ($1 != null){
                        Event e = (Event) $1;
                        current_container.AddEvent (e);
                }
++
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.Allowed;
          }
        | interface_indexer_declaration
          { 
                Indexer i = (Indexer) $1;
  
                current_container.AddIndexer (i);
++
++              if (RootContext.Documentation != null)
++                      Lexer.doc_state = XmlCommentState.Allowed;
          }
        ;
  
@@@ -1466,6 -1466,6 +1575,8 @@@ interface_method_declaratio
  
                $$ = new Method (current_class, generic, (Expression) $3, (int) $2, true, name,
                                 (Parameters) $6, (Attributes) $1, lexer.Location);
++              if (RootContext.Documentation != null)
++                      ((Method) $$).DocComment = Lexer.consume_doc_comment ();
          }
        | opt_attributes opt_new VOID namespace_or_type_name
          OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
  
                $$ = new Method (current_class, generic, TypeManager.system_void_expr, (int) $2,
                                 true, name, (Parameters) $6, (Attributes) $1, lexer.Location);
++              if (RootContext.Documentation != null)
++                      ((Method) $$).DocComment = Lexer.consume_doc_comment ();
          }
        ;
  
@@@ -1511,6 -1511,6 +1624,8 @@@ interface_property_declaratio
                $$ = new Property (current_class, (Expression) $3, (int) $2, true,
                                   new MemberName ((string) $4), (Attributes) $1,
                                   pinfo.Get, pinfo.Set, lexer.Location);
++              if (RootContext.Documentation != null)
++                      ((Property) $$).DocComment = Lexer.consume_doc_comment ();
          }
        | opt_attributes
          opt_new
@@@ -1537,6 -1535,6 +1652,8 @@@ interface_event_declaratio
                $$ = new EventField (current_class, (Expression) $4, (int) $2, true,
                                     new MemberName ((string) $5), null,
                                     (Attributes) $1, lexer.Location);
++              if (RootContext.Documentation != null)
++                      ((EventField) $$).DocComment = Lexer.consume_doc_comment ();
          }
        | opt_attributes opt_new EVENT type error {
                CheckIdentifierToken (yyToken);
@@@ -1567,6 -1565,6 +1684,8 @@@ interface_indexer_declaratio
                                  new MemberName (TypeContainer.DefaultIndexerName),
                                  (int) $2, true, (Parameters) $6, (Attributes) $1,
                                  info.Get, info.Set, lexer.Location);
++              if (RootContext.Documentation != null)
++                      ((Indexer) $$).DocComment = ConsumeStoredComment ();
          }
        ;
  
@@@ -1590,6 -1588,6 +1709,9 @@@ operator_declaratio
                        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 ();
  
@@@ -1619,12 -1617,12 +1741,18 @@@ operator_declarato
                        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
                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);
 -             Parameter [] pars = new Parameter [2];
++              Expression typeL = (Expression) $5;
++              Expression typeR = (Expression) $8;
 -             pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null);
 -             pars [1] = new Parameter ((Expression) $8, (string) $9, Parameter.Modifier.NONE, null);
++             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
        ;
@@@ -1721,6 -1719,6 +1857,9 @@@ constructor_declaratio
                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){
                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);
          }
        ;
  
@@@ -1805,9 -1803,9 +1952,16 @@@ opt_finalize
          ;
          
  destructor_declaration
--      : opt_attributes opt_finalizer TILDE IDENTIFIER OPEN_PARENS CLOSE_PARENS block
++      : opt_attributes opt_finalizer TILDE 
++        {
++              if (RootContext.Documentation != null) {
++                      tmpComment = Lexer.consume_doc_comment ();
++                      Lexer.doc_state = XmlCommentState.NotAllowed;
++              }
++        }
++        IDENTIFIER OPEN_PARENS CLOSE_PARENS block
          {
--              if ((string) $4 != current_container.Basename){
++              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");
                        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);
                }
          }
@@@ -1853,7 -1851,7 +2009,11 @@@ event_declaratio
                                lexer.Location);
  
                        current_container.AddEvent (e);
--                                     
++
++                      if (RootContext.Documentation != null) {
++                              e.DocComment = Lexer.consume_doc_comment ();
++                              Lexer.doc_state = XmlCommentState.Allowed;
++                      }
                }
          }
        | opt_attributes
                                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;
                }
                        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;
          }
        ;
  
@@@ -2010,6 -2008,6 +2177,8 @@@ indexer_declaratio
                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);
                
@@@ -2029,6 -2027,6 +2198,10 @@@ indexer_declarato
                } 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);
          }
                } else if (pars.FixedParameters == null && pars.ArrayParameter == null){
                        Report.Error (1551, lexer.Location, "Indexers must have at least one parameter");
                }
++
                MemberName name = (MemberName) $2;
                if (name.TypeArguments != null)
                        syntax_error (lexer.Location, "an indexer can't have type arguments");
  
                $$ = new IndexerDeclaration ((Expression) $1, name, pars);
++
++              if (RootContext.Documentation != null) {
++                      tmpComment = Lexer.consume_doc_comment ();
++                      Lexer.doc_state = XmlCommentState.Allowed;
++              }
          }
        ;
  
@@@ -2054,7 -2052,7 +2233,10 @@@ enum_declaratio
        : 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
          { 
                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 ();
@@@ -2083,9 -2081,9 +2269,20 @@@ opt_enum_bas
        ;
  
  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;
          }
        ;
  
@@@ -2115,15 -2113,15 +2312,31 @@@ enum_member_declaration
  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;
          }
        ;
  
@@@ -2138,6 -2136,6 +2351,11 @@@ delegate_declaratio
                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);
  
                        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);
  
@@@ -3231,9 -3229,9 +3454,18 @@@ class_declaratio
  
                current_class.SetParameterInfo ((ArrayList) $8);
  
++              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;
@@@ -4362,6 -4360,6 +4594,7 @@@ public class VariableDeclaration 
        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)
        {
@@@ -4706,5 -4698,5 +4939,13 @@@ void CheckIdentifierToken (int yyToken
        CheckToken (1041, yyToken, "Identifier expected");
  }
  
++string ConsumeStoredComment ()
++{
++      string s = tmpComment;
++      tmpComment = null;
++      Lexer.doc_state = XmlCommentState.Allowed;
++      return s;
++}
++
  /* end end end */
  }
index 3785eb09bf2dc42a36ef48e07198457434f63940,3785eb09bf2dc42a36ef48e07198457434f63940..f147ec537637dc3a251f6ce415373ce8a7b592b5
@@@ -7,6 -7,6 +7,7 @@@
  // Licensed under the terms of the GNU GPL
  //
  // (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
++// (C) 2004 Novell, Inc
  //
  
  /*
@@@ -43,6 -43,6 +44,17 @@@ namespace Mono.CShar
                bool handle_constraints = false;
                bool handle_typeof = 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
                //
                                handle_typeof = value;
                        }
                }
--              
++
++              public XmlCommentState doc_state {
++                      get { return xmlDocState; }
++                      set {
++                              if (value == XmlCommentState.Allowed) {
++                                      check_incorrect_doc_comment ();
++                                      consume_doc_comment ();
++                              }
++                              xmlDocState = value;
++                      }
++              }
++
                //
                // Class variables
                // 
                                        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
                        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;
                {
                        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;
                                
                                        if (d == '/'){
                                                getChar ();
++                                              if (RootContext.Documentation != null && peekChar () == '/') {
++                                                      getChar ();
++                                                      // Allow only ///ws.
++                                                      // Don't allow ////.
++                                                      if ((d = peekChar ()) == ' ' || d == '\t') {
++                                                              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'){
                                                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 () == '/'){
                                                                col++;
                                                                break;
                                                        }
++                                                      if (docAppend)
++                                                              xml_comment_buffer.Append ((char) d);
++                                                      
                                                        if (d == '\n'){
                                                                line++;
                                                                ref_line++;
                                                                tokens_seen = false;
                                                        }
                                                }
++                                              if (docAppend)
++                                                      update_formatted_doc_comment (currentCommentStart);
                                                continue;
                                        }
                                        goto is_punct_label;
                        return Token.ERROR;
                }
  
++              //
++              // 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' || c == '\n')
++                              xml_comment_buffer.Append (Environment.NewLine);
++              }
++
++              //
++              // 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).Replace ("\r", "").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 (Environment.NewLine, 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) {
                                
                }
        }
++
++      //
++      // 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 9fb3d83eb9a2f31276d0818f59670f782eac55be,6c727a79a0a9cc261392cda1655fe66fe9a334b4..f3ac24f95594b18fcded3a291f91e515f83e7bb7
@@@ -7,6 -7,6 +7,7 @@@
  // Licensed under the terms of the GNU GPL
  //
  // (C) 2001 Ximian, Inc (http://www.ximian.com)
++// (C) 2004 Novell, Inc
  //
  // TODO: Move the method verification stuff from the class.cs and interface.cs here
  //
@@@ -17,6 -17,6 +18,7 @@@ using System.Collections
  using System.Globalization;
  using System.Reflection.Emit;
  using System.Reflection;
++using System.Xml;
  
  namespace Mono.CSharp {
  
                /// </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
                /// <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;
  
                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>
                        IDictionaryEnumerator it = parent.member_hash.GetEnumerator ();
                        while (it.MoveNext ()) {
                                hash [it.Key] = ((ArrayList) it.Value).Clone ();
--                        }
++                       }
                                  
                        return hash;
                }
index 0ecd1addd17c99c5fb8990ac03abd992cdde848c,36a5b481e5fb4b4edd9ef0d95c9ba55beb0ec26d..bdd1e7366590dd0bbccc8bbd894ac4a84ca71140
@@@ -684,6 -684,6 +684,13 @@@ namespace Mono.CSharp 
                        }
                }
  
++              //
++              //   Represents header string for documentation comment.
++              //
++              public override string DocCommentHeader {
++                      get { return "T:"; }
++              }
++
                protected override void VerifyObsoleteAttribute()
                {
                        CheckUsageOfObsoleteAttribute (ret_type);
diff --cc mcs/gmcs/doc.cs
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c33e0e1ef68a019101dcdfcfc9ab4e5aa78c9376
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,809 @@@
++//
++// doc.cs: Support for XML documentation comment.
++//
++// Author:
++//    Atsushi Enomoto <atsushi@ximian.com>
++//
++// Licensed under the terms of the GNU GPL
++//
++// (C) 2004 Novell, Inc.
++//
++//
++using System;
++using System.Collections;
++using System.Collections.Specialized;
++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.DefaultStaticConstructor != null)
++                              t.DefaultStaticConstructor.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.Parts != null) {
++                              IDictionary comments = RootContext.Documentation.PartialComments;
++                              foreach (ClassPart cp in t.Parts) {
++                                      if (cp.DocComment == null)
++                                              continue;
++                                      comments [cp] = cp;
++                              }
++                      }
++
++                      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 readonly string lineHead =
++                      Environment.NewLine + "            ";
++
++              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 =
++                                      normalized.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 = lineHead + String.Join (
++                                      lineHead, 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, see);
++                                      foreach (XmlElement seealso in n.SelectNodes (".//seealso"))
++                                              HandleSeeAlso (mc, dsTarget, seealso);
++                                      foreach (XmlElement see in n.SelectNodes (".//exception"))
++                                              HandleException (mc, dsTarget, see);
++                              }
++
++                              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, XmlElement see)
++              {
++                      HandleXrefCommon (mc, ds, see);
++              }
++
++              //
++              // Handles <seealso> elements.
++              //
++              private static void HandleSeeAlso (MemberCore mc,
++                      DeclSpace ds, XmlElement seealso)
++              {
++                      HandleXrefCommon (mc, ds, seealso);
++              }
++
++              //
++              // Handles <exception> elements.
++              //
++              private static void HandleException (MemberCore mc,
++                      DeclSpace ds, XmlElement seealso)
++              {
++                      HandleXrefCommon (mc, ds, 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 name, DeclSpace ds, bool allowAlias)
++              {
++                      bool isArray = false;
++                      string identifier = name;
++                      if (name [name.Length - 1] == ']') {
++                              string tmp = name.Substring (0, name.Length - 1).Trim (wsChars);
++                              if (tmp [tmp.Length - 1] == '[') {
++                                      identifier = tmp.Substring (0, tmp.Length - 1).Trim (wsChars);
++                                      isArray = true;
++                              }
++                      }
++                      Type t = FindDocumentedTypeNonArray (mc, identifier,
++                              ds, allowAlias);
++                      if (t != null && isArray)
++                              t = Array.CreateInstance (t, 0).GetType ();
++                      return t;
++              }
++
++              private static Type FindDocumentedTypeNonArray (MemberCore mc,
++                      string identifier, DeclSpace ds, bool allowAlias)
++              {
++                      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);
++                      }
++                      if (allowAlias) {
++                              string alias = ds.LookupAlias (identifier);
++                              if (alias != null)
++                                      identifier = alias;
++                      }
++                      Type t = ds.FindType (mc.Location, identifier);
++                      if (t == null)
++                              t = TypeManager.LookupTypeDirect (identifier);
++                      return t;
++              }
++
++              //
++              // 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, true);
++                              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, 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; // "x:" are stripped
++                      string name; // method invokation "(...)" are removed
++                      string identifiers; // array indexer "[]" are removed
++                      string parameters; // method parameter list
++
++                      // 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] == ')') {
++                              name = signature.Substring (0, parensPos).Trim (wsChars);
++                              parameters = signature.Substring (parensPos + 1, signature.Length - parensPos - 2);
++                      }
++                      else {
++                              name = signature;
++                              parameters = String.Empty;
++                      }
++
++                      string identifier = name;
++
++                      if (name.Length > 0 && name [name.Length - 1] == ']') {
++                              string tmp = name.Substring (0, name.Length - 1).Trim (wsChars);
++                              if (tmp [tmp.Length - 1] == '[')
++                                      identifier = tmp.Substring (0, tmp.Length - 1).Trim (wsChars);
++                      }
++
++                      // 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) {
++                                      if (nameElem.EndsWith ("[]") &&
++                                              Tokenizer.IsValidIdentifier (
++                                              nameElem.Substring (
++                                              0, nameElem.Length - 2)))
++                                              continue;
++
++                                      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);
++                                      Type paramType = FindDocumentedType (mc, paramTypeName, ds, true);
++                                      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 [];
++                              StringBuilder sb = new StringBuilder ();
++                              sb.Append ('(');
++                              for (int i = 0; i < parameterTypes.Length; i++) {
++                                      Type t = parameterTypes [i];
++                                      if (sb.Length > 1)
++                                              sb.Append (',');
++                                      sb.Append (t.FullName.Replace ('+', '.'));
++                              }
++                              sb.Append (')');
++                              parameters = sb.ToString ();
++                      }
++
++                      Type type = FindDocumentedType (mc, name, ds, true);
++                      if (type != null) {
++                              xref.SetAttribute ("cref", "T:" + type.FullName.Replace ("+", "."));
++                              return; // a type
++                      }
++
++                      // don't use identifier here. System[] is not alloed.
++                      if (Namespace.IsNamespace (name)) {
++                              xref.SetAttribute ("cref", "N:" + name);
++                              return; // a namespace
++                      }
++
++                      int period = name.LastIndexOf ('.');
++                      if (period > 0) {
++                              string typeName = name.Substring (0, period);
++                              string memberName = name.Substring (period + 1);
++                              type = FindDocumentedType (mc, typeName, ds, false);
++                              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 + parameters);
++                                              return; // a member of a type
++                                      }
++                              }
++                      }
++                      else {
++                              int warnResult;
++                              MemberInfo mi = FindDocumentedMember (mc, ds.TypeBuilder, name, parameterTypes, ds, out warnResult, cref);
++                              if (warnResult > 0)
++                                      return;
++                              if (mi != null) {
++                                      xref.SetAttribute ("cref", GetMemberDocHead (mi.MemberType) + ds.TypeBuilder.FullName.Replace ("+", ".") + "." + name);
++                                      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", "!:" + name);
++              }
++
++              //
++              // 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 ("+", "."));
++                              }
++                              paramSpec = psb.ToString ();
++                      }
++                      if (parr != null)
++                              paramSpec += String.Concat (
++                                      paramSpec == String.Empty ? "(" : ",",
++                                      parr.ParameterType.FullName.Replace ("+", "."));
++
++                      if (paramSpec.Length > 0)
++                              paramSpec += ")";
++
++                      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 (string xml_output_filename)
++              {
++                      docfilename = xml_output_filename;
++                      XmlDocumentation = new XmlDocument ();
++                      XmlDocumentation.PreserveWhitespace = false;
++              }
++
++              private string docfilename;
++
++              //
++              // 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.
++              // Keys are included filenames, values are XmlDocuments.
++              //
++              public Hashtable StoredDocuments = new Hashtable ();
++
++              //
++              // Stores comments on partial types (should handle uniquely).
++              // Keys are PartialContainers, values are comment strings
++              // (didn't use StringBuilder; usually we have just 2 or more).
++              //
++              public IDictionary PartialComments = new ListDictionary ();
++
++              //
++              // Outputs XML documentation comment from tokenized comments.
++              //
++              public bool OutputDocComment (string asmfilename)
++              {
++                      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 ();
++                              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 = RootContext.Tree.Types;
++                      if (root.Interfaces != null)
++                              foreach (Interface i in root.Interfaces) 
++                                      DocUtil.GenerateTypeDocComment (i, null);
++
++                      if (root.Types != null)
++                              foreach (TypeContainer tc in root.Types)
++                                      DocUtil.GenerateTypeDocComment (tc, null);
++
++                      if (root.Parts != null) {
++                              IDictionary comments = PartialComments;
++                              foreach (ClassPart cp in root.Parts) {
++                                      if (cp.DocComment == null)
++                                              continue;
++                                      comments [cp] = cp;
++                              }
++                      }
++
++                      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);
++
++                      IDictionary table = new ListDictionary ();
++                      foreach (ClassPart cp in PartialComments.Keys) {
++                              table [cp.PartialContainer] += cp.DocComment;
++                      }
++                      foreach (PartialContainer pc in table.Keys) {
++                              pc.DocComment = table [pc] as string;
++                              DocUtil.GenerateDocComment (pc, null);
++                      }
++              }
++      }
++}
index db104221853ca96a1c3a7917f7290be75238e4ce,db104221853ca96a1c3a7917f7290be75238e4ce..1dc2abe4215d4a385d01d85f2c56373b7b964cfe
@@@ -6,6 -6,6 +6,7 @@@
  // Licensed under the terms of the GNU GPL
  //
  // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
++// (C) 2004 Novell, Inc
  //
  
  namespace Mono.CSharp
@@@ -18,6 -18,6 +19,8 @@@
        using System.IO;
        using System.Text;
        using System.Globalization;
++      using System.Xml;
++      using System.Diagnostics;
  
        public enum Target {
                Library, Exe, Module, WinExe
                                "   -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" + 
                        }
                        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
++                              RootContext.Documentation = new Documentation (value);
                                return true;
                        }
                        case "/lib": {
                        if (timestamps)
                                ShowTime ("Resolving tree");
                        RootContext.ResolveTree ();
++
                        if (Report.Errors > 0)
                                return false;
                        if (timestamps)
                        RootContext.PopulateTypes ();
                        RootContext.DefineTypes ();
                        
++                      if (RootContext.Documentation != null &&
++                              !RootContext.Documentation.OutputDocComment (
++                                      output_file))
++                              return false;
++
                        TypeManager.InitCodeHelpers ();
  
                        //
  #endif
                        return (Report.Errors == 0);
                }
--
        }
  
        //
index a9974b1ba9d4614f7f0fc816d53657237cba7530,a9974b1ba9d4614f7f0fc816d53657237cba7530..1ae16150f746a25a9d325be482dd50a317d17eda
@@@ -14,6 -14,6 +14,7 @@@ using System.Collections
  using System.Reflection;
  using System.Reflection.Emit;
  using System.Globalization;
++using System.Xml;
  
  namespace Mono.CSharp {
  
                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;
                
                ///   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__'");
                        }
  
                        EnumMember em = new EnumMember (this, expr, name, loc, opt_attrs);
++                      em.DocComment = documentation;
                        if (!AddToContainer (em, false, name, ""))
                                return;
  
                {
                        // 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 0f1f076ca6837a65f3284d05dd70bbe2441f6d19,aeaf4e645f45952ffb89c58050c76d389226fa75..f792d213ac618eb576c6d5b51dd6f55ae10a29a2
@@@ -7,12 -7,12 +7,14 @@@
  // Licensed under the terms of the GNU GPL
  //
  // (C) 2001 Ximian, Inc (http://www.ximian.com)
++// (C) 2004 Novell, Inc
  
  using System;
  using System.Collections;
  using System.Reflection;
  using System.Reflection.Emit;
  using System.Diagnostics;
++using System.Xml;
  
  namespace Mono.CSharp {
  
                public static string StrongNameKeyContainer;
                public static bool StrongNameDelaySign = false;
  
++              //
++              // If set, enable XML documentation generation
++              //
++              public static Documentation Documentation;
++
                //
                // Constructor
                //