Merge pull request #949 from ermshiperete/bug-novell-463149
[mono.git] / mcs / mcs / doc.cs
index fd4e394b75b1286fda8ea715ff91bc7e5053a20c..35fe5852930447dcc8cbf3095a34f319638fa32e 100644 (file)
@@ -8,6 +8,7 @@
 // Dual licensed under the terms of the MIT X11 or GNU GPL
 //
 // Copyright 2004 Novell, Inc.
+// Copyright 2011 Xamarin Inc
 //
 //
 
@@ -31,6 +32,7 @@ namespace Mono.CSharp
                readonly XmlDocument XmlDocumentation;
 
                readonly ModuleContainer module;
+               readonly ModuleContainer doc_module;
 
                //
                // The output for XML documentation.
@@ -45,8 +47,13 @@ namespace Mono.CSharp
                //
                Dictionary<string, XmlDocument> StoredDocuments = new Dictionary<string, XmlDocument> ();
 
+               ParserSession session;
+
                public DocumentationBuilder (ModuleContainer module)
                {
+                       doc_module = new ModuleContainer (module.Compiler);
+                       doc_module.DocumentationBuilder = this;
+
                        this.module = module;
                        XmlDocumentation = new XmlDocument ();
                        XmlDocumentation.PreserveWhitespace = false;
@@ -140,16 +147,17 @@ namespace Mono.CSharp
                                }
 
                                // FIXME: it could be done with XmlReader
-                               DeclSpace ds_target = mc as DeclSpace;
-                               if (ds_target == null)
-                                       ds_target = mc.Parent;
 
                                foreach (XmlElement see in n.SelectNodes (".//see"))
-                                       HandleSee (mc, ds_target, see);
+                                       HandleSee (mc, see);
                                foreach (XmlElement seealso in n.SelectNodes (".//seealso"))
-                                       HandleSeeAlso (mc, ds_target, seealso);
+                                       HandleSeeAlso (mc, seealso);
                                foreach (XmlElement see in n.SelectNodes (".//exception"))
-                                       HandleException (mc, ds_target, see);
+                                       HandleException (mc, see);
+                               foreach (XmlElement node in n.SelectNodes (".//typeparam"))
+                                       HandleTypeParam (mc, node);
+                               foreach (XmlElement node in n.SelectNodes (".//typeparamref"))
+                                       HandleTypeParamRef (mc, node);
                        }
 
                        n.WriteTo (XmlCommentOutput);
@@ -164,28 +172,31 @@ namespace Mono.CSharp
                        bool keep_include_node = false;
                        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);
                                keep_include_node = true;
-                       }
-                       else if (path.Length == 0) {
+                       } else if (path.Length == 0) {
                                Report.Warning (1590, 1, mc.Location, "Invalid XML `include' element. Missing `path' attribute");
                                el.ParentNode.InsertBefore (el.OwnerDocument.CreateComment (" Include tag is invalid "), el);
                                keep_include_node = true;
-                       }
-                       else {
+                       } else {
                                XmlDocument doc;
-                               if (!StoredDocuments.TryGetValue (file, out doc)) {
+                               Exception exception = null;
+                               var full_path = Path.Combine (Path.GetDirectoryName (mc.Location.NameFullPath), file);
+
+                               if (!StoredDocuments.TryGetValue (full_path, out doc)) {
                                        try {
                                                doc = new XmlDocument ();
-                                               doc.Load (file);
-                                               StoredDocuments.Add (file, doc);
-                                       } catch (Exception) {
+                                               doc.Load (full_path);
+                                               StoredDocuments.Add (full_path, doc);
+                                       } catch (Exception e) {
+                                               exception = e;
                                                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);
                                        }
                                }
+
                                if (doc != null) {
                                        try {
                                                XmlNodeList nl = doc.SelectNodes (path);
@@ -197,51 +208,102 @@ namespace Mono.CSharp
                                                foreach (XmlNode n in nl)
                                                        el.ParentNode.InsertBefore (el.OwnerDocument.ImportNode (n, true), el);
                                        } catch (Exception ex) {
+                                               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 (exception != null) {
+                                       Report.Warning (1589, 1, mc.Location, "Unable to include XML fragment `{0}' of file `{1}'. {2}",
+                                               path, file, exception.Message);
+                               }
                        }
+
                        return keep_include_node;
                }
 
                //
                // Handles <see> elements.
                //
-               void HandleSee (MemberCore mc, DeclSpace ds, XmlElement see)
+               void HandleSee (MemberCore mc, XmlElement see)
                {
-                       HandleXrefCommon (mc, ds, see);
+                       HandleXrefCommon (mc, see);
                }
 
                //
                // Handles <seealso> elements.
                //
-               void HandleSeeAlso (MemberCore mc, DeclSpace ds, XmlElement seealso)
+               void HandleSeeAlso (MemberCore mc, XmlElement seealso)
                {
-                       HandleXrefCommon (mc, ds, seealso);
+                       HandleXrefCommon (mc, seealso);
                }
 
                //
                // Handles <exception> elements.
                //
-               void HandleException (MemberCore mc, DeclSpace ds, XmlElement seealso)
+               void HandleException (MemberCore mc, XmlElement seealso)
+               {
+                       HandleXrefCommon (mc, seealso);
+               }
+
+               //
+               // Handles <typeparam /> node
+               //
+               static void HandleTypeParam (MemberCore mc, XmlElement node)
+               {
+                       if (!node.HasAttribute ("name"))
+                               return;
+
+                       string tp_name = node.GetAttribute ("name");
+                       if (mc.CurrentTypeParameters != null) {
+                               if (mc.CurrentTypeParameters.Find (tp_name) != null)
+                                       return;
+                       }
+                       
+                       // TODO: CS1710, CS1712
+                       
+                       mc.Compiler.Report.Warning (1711, 2, mc.Location,
+                               "XML comment on `{0}' has a typeparam name `{1}' but there is no type parameter by that name",
+                               mc.GetSignatureForError (), tp_name);
+               }
+
+               //
+               // Handles <typeparamref /> node
+               //
+               static void HandleTypeParamRef (MemberCore mc, XmlElement node)
                {
-                       HandleXrefCommon (mc, ds, seealso);
+                       if (!node.HasAttribute ("name"))
+                               return;
+
+                       string tp_name = node.GetAttribute ("name");
+                       var member = mc;
+                       do {
+                               if (member.CurrentTypeParameters != null) {
+                                       if (member.CurrentTypeParameters.Find (tp_name) != null)
+                                               return;
+                               }
+
+                               member = member.Parent;
+                       } while (member != null);
+
+                       mc.Compiler.Report.Warning (1735, 2, mc.Location,
+                               "XML comment on `{0}' has a typeparamref name `{1}' that could not be resolved",
+                               mc.GetSignatureForError (), tp_name);
                }
 
                FullNamedExpression ResolveMemberName (IMemberContext context, MemberName mn)
                {
                        if (mn.Left == null)
-                               return context.LookupNamespaceOrType (mn.Name, mn.Arity, Location.Null, /*ignore_cs0104=*/ false);
+                               return context.LookupNamespaceOrType (mn.Name, mn.Arity, LookupMode.Probing, Location.Null);
 
                        var left = ResolveMemberName (context, mn.Left);
-                       var ns = left as Namespace;
+                       var ns = left as NamespaceExpression;
                        if (ns != null)
-                               return ns.Lookup (context, mn.Name, mn.Arity, Location.Null);
+                               return ns.LookupTypeOrNamespace (context, mn.Name, mn.Arity, LookupMode.Probing, Location.Null);
 
                        TypeExpr texpr = left as TypeExpr;
                        if (texpr != null) {
-                               var found = MemberCache.FindNestedType (texpr.Type, ParsedName.Name, ParsedName.Arity);
+                               var found = MemberCache.FindNestedType (texpr.Type, mn.Name, mn.Arity);
                                if (found != null)
                                        return new TypeExpression (found, Location.Null);
 
@@ -254,7 +316,7 @@ namespace Mono.CSharp
                //
                // Processes "see" or "seealso" elements from cref attribute.
                //
-               void HandleXrefCommon (MemberCore mc, DeclSpace ds, XmlElement xref)
+               void HandleXrefCommon (MemberCore mc, XmlElement xref)
                {
                        string cref = xref.GetAttribute ("cref");
                        // when, XmlReader, "if (cref == null)"
@@ -270,15 +332,18 @@ namespace Mono.CSharp
 
                        var encoding = module.Compiler.Settings.Encoding;
                        var s = new MemoryStream (encoding.GetBytes (cref));
-                       SeekableStreamReader seekable = new SeekableStreamReader (s, encoding);
 
-                       var source_file = new CompilationSourceFile ("{documentation}", "", 1);
-                       var doc_module = new ModuleContainer (module.Compiler);
-                       doc_module.DocumentationBuilder = this;
-                       source_file.NamespaceContainer = new NamespaceEntry (doc_module, null, source_file, null);
+                       var source_file = new CompilationSourceFile (doc_module, mc.Location.SourceFile);
+                       var report = new Report (doc_module.Compiler, new NullReportPrinter ());
+
+                       if (session == null)
+                               session = new ParserSession {
+                                       UseJayGlobalArrays = true
+                               };
 
-                       Report parse_report = new Report (new NullReportPrinter ());
-                       var parser = new CSharpParser (seekable, source_file, parse_report);
+                       SeekableStreamReader seekable = new SeekableStreamReader (s, encoding, session.StreamReaderBuffer);
+
+                       var parser = new CSharpParser (seekable, source_file, report, session);
                        ParsedParameters = null;
                        ParsedName = null;
                        ParsedBuiltinType = null;
@@ -286,7 +351,7 @@ namespace Mono.CSharp
                        parser.Lexer.putback_char = Tokenizer.DocumentationXref;
                        parser.Lexer.parsing_generic_declaration_doc = true;
                        parser.parse ();
-                       if (parse_report.Errors > 0) {
+                       if (report.Errors > 0) {
                                Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
                                        mc.GetSignatureForError (), cref);
 
@@ -302,7 +367,7 @@ namespace Mono.CSharp
                        // Try built-in type first because we are using ParsedName as identifier of
                        // member names on built-in types
                        //
-                       if (ParsedBuiltinType != null && ParsedParameters == null) {
+                       if (ParsedBuiltinType != null && (ParsedParameters == null || ParsedName != null)) {
                                member = ParsedBuiltinType.Type;
                        } else {
                                member = null;
@@ -318,9 +383,9 @@ namespace Mono.CSharp
                                        } else if (ParsedName.Left != null) {
                                                fne = ResolveMemberName (mc, ParsedName.Left);
                                                if (fne != null) {
-                                                       var ns = fne as Namespace;
+                                                       var ns = fne as NamespaceExpression;
                                                        if (ns != null) {
-                                                               fne = ns.Lookup (mc, ParsedName.Name, ParsedName.Arity, Location.Null);
+                                                               fne = ns.LookupTypeOrNamespace (mc, ParsedName.Name, ParsedName.Arity, LookupMode.Probing, Location.Null);
                                                                if (fne != null) {
                                                                        member = fne.Type;
                                                                }
@@ -345,8 +410,15 @@ namespace Mono.CSharp
                                }
 
                                if (ParsedParameters != null) {
-                                       foreach (var pp in ParsedParameters) {
-                                               pp.Resolve (mc);
+                                       var old_printer = mc.Module.Compiler.Report.SetPrinter (new NullReportPrinter ());
+                                       try {
+                                               var context = new DocumentationMemberContext (mc, ParsedName ?? MemberName.Null);
+
+                                               foreach (var pp in ParsedParameters) {
+                                                       pp.Resolve (context);
+                                               }
+                                       } finally {
+                                               mc.Module.Compiler.Report.SetPrinter (old_printer);
                                        }
                                }
 
@@ -380,13 +452,15 @@ namespace Mono.CSharp
                                                                        if (m.Kind == MemberKind.Operator && !ParsedOperator.HasValue)
                                                                                continue;
 
+                                                                       var pm_params = pm.Parameters;
+
                                                                        int i;
                                                                        for (i = 0; i < parsed_param_count; ++i) {
                                                                                var pparam = ParsedParameters[i];
 
-                                                                               if (i >= pm.Parameters.Count || pparam == null ||
-                                                                                       pparam.TypeSpec != pm.Parameters.Types[i] ||
-                                                                                       (pparam.Modifier & Parameter.Modifier.SignatureMask) != (pm.Parameters.FixedParameters[i].ModFlags & Parameter.Modifier.SignatureMask)) {
+                                                                               if (i >= pm_params.Count || pparam == null || pparam.TypeSpec == null ||
+                                                                                       !TypeSpecComparer.Override.IsEqual (pparam.TypeSpec, pm_params.Types[i]) ||
+                                                                                       (pparam.Modifier & Parameter.Modifier.RefOutMask) != (pm_params.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) {
 
                                                                                        if (i > parameters_match) {
                                                                                                parameters_match = i;
@@ -406,7 +480,7 @@ namespace Mono.CSharp
                                                                                        continue;
                                                                                }
                                                                        } else {
-                                                                               if (parsed_param_count != pm.Parameters.Count)
+                                                                               if (parsed_param_count != pm_params.Count)
                                                                                        continue;
                                                                        }
                                                                }
@@ -559,10 +633,102 @@ namespace Mono.CSharp
                }
        }
 
+       //
+       // Type lookup of documentation references uses context of type where
+       // the reference is used but type parameters from cref value
+       //
+       sealed class DocumentationMemberContext : IMemberContext
+       {
+               readonly MemberCore host;
+               MemberName contextName;
+
+               public DocumentationMemberContext (MemberCore host, MemberName contextName)
+               {
+                       this.host = host;
+                       this.contextName = contextName;
+               }
+
+               public TypeSpec CurrentType {
+                       get {
+                               return host.CurrentType;
+                       }
+               }
+
+               public TypeParameters CurrentTypeParameters {
+                       get {
+                               return contextName.TypeParameters;
+                       }
+               }
+
+               public MemberCore CurrentMemberDefinition {
+                       get {
+                               return host.CurrentMemberDefinition;
+                       }
+               }
+
+               public bool IsObsolete {
+                       get {
+                               return false;
+                       }
+               }
+
+               public bool IsUnsafe {
+                       get {
+                               return host.IsStatic;
+                       }
+               }
+
+               public bool IsStatic {
+                       get {
+                               return host.IsStatic;
+                       }
+               }
+
+               public ModuleContainer Module {
+                       get {
+                               return host.Module;
+                       }
+               }
+
+               public string GetSignatureForError ()
+               {
+                       return host.GetSignatureForError ();
+               }
+
+               public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
+               {
+                       return null;
+               }
+
+               public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
+               {
+                       if (arity == 0) {
+                               var tp = CurrentTypeParameters;
+                               if (tp != null) {
+                                       for (int i = 0; i < tp.Count; ++i) {
+                                               var t = tp[i];
+                                               if (t.Name == name) {
+                                                       t.Type.DeclaredPosition = i;
+                                                       return new TypeParameterExpr (t, loc);
+                                               }
+                                       }
+                               }
+                       }
+
+                       return host.Parent.LookupNamespaceOrType (name, arity, mode, loc);
+               }
+
+               public FullNamedExpression LookupNamespaceAlias (string name)
+               {
+                       throw new NotImplementedException ();
+               }
+       }
+
        class DocumentationParameter
        {
                public readonly Parameter.Modifier Modifier;
                public FullNamedExpression Type;
+               TypeSpec type;
 
                public DocumentationParameter (Parameter.Modifier modifier, FullNamedExpression type)
                        : this (type)
@@ -577,13 +743,13 @@ namespace Mono.CSharp
 
                public TypeSpec TypeSpec {
                        get {
-                               return Type == null ? null : Type.Type;
+                               return type;
                        }
                }
 
                public void Resolve (IMemberContext context)
                {
-                       Type = Type.ResolveAsTypeTerminal (context, true);
+                       type = Type.ResolveAsType (context);
                }
        }
 }