// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2004 Novell, Inc.
+// Copyright 2011 Xamarin Inc
//
//
readonly XmlDocument XmlDocumentation;
readonly ModuleContainer module;
+ readonly ModuleContainer doc_module;
//
// The output for XML documentation.
//
- public XmlWriter XmlCommentOutput;
+ XmlWriter XmlCommentOutput;
static readonly string line_head = Environment.NewLine + " ";
public DocumentationBuilder (ModuleContainer module)
{
+ doc_module = new ModuleContainer (module.Compiler);
+ doc_module.DocumentationBuilder = this;
+
this.module = module;
XmlDocumentation = new XmlDocument ();
XmlDocumentation.PreserveWhitespace = false;
XmlElement el = n as XmlElement;
if (el != null) {
- mc.OnGenerateDocComment (el);
+ var pm = mc as IParametersMember;
+ if (pm != null) {
+ CheckParametersComments (mc, pm, el);
+ }
// FIXME: it could be done with XmlReader
XmlNodeList nl = n.SelectNodes (".//include");
}
// FIXME: it could be done with XmlReader
- DeclSpace ds_target = mc as DeclSpace;
+ var ds_target = mc as TypeContainer;
if (ds_target == null)
ds_target = mc.Parent;
HandleSeeAlso (mc, ds_target, seealso);
foreach (XmlElement see in n.SelectNodes (".//exception"))
HandleException (mc, ds_target, see);
+ foreach (XmlElement node in n.SelectNodes (".//typeparam"))
+ HandleTypeParam (mc, node);
+ foreach (XmlElement node in n.SelectNodes (".//typeparamref"))
+ HandleTypeParamRef (mc, node);
}
n.WriteTo (XmlCommentOutput);
//
// Handles <see> elements.
//
- void HandleSee (MemberCore mc, DeclSpace ds, XmlElement see)
+ void HandleSee (MemberCore mc, TypeContainer ds, XmlElement see)
{
HandleXrefCommon (mc, ds, see);
}
//
// Handles <seealso> elements.
//
- void HandleSeeAlso (MemberCore mc, DeclSpace ds, XmlElement seealso)
+ void HandleSeeAlso (MemberCore mc, TypeContainer ds, XmlElement seealso)
{
HandleXrefCommon (mc, ds, seealso);
}
//
// Handles <exception> elements.
//
- void HandleException (MemberCore mc, DeclSpace ds, XmlElement seealso)
+ void HandleException (MemberCore mc, TypeContainer ds, XmlElement seealso)
{
HandleXrefCommon (mc, ds, seealso);
}
+ //
+ // Handles <typeparam /> node
+ //
+ 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
+ //
+ void HandleTypeParamRef (MemberCore mc, XmlElement node)
+ {
+ 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;
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) {
//
// Processes "see" or "seealso" elements from cref attribute.
//
- void HandleXrefCommon (MemberCore mc, DeclSpace ds, XmlElement xref)
+ void HandleXrefCommon (MemberCore mc, TypeContainer ds, XmlElement xref)
{
string cref = xref.GetAttribute ("cref");
// when, XmlReader, "if (cref == null)"
if (cref.Length > 2 && cref [1] == ':')
return;
+ // Additional symbols for < and > are allowed for easier XML typing
+ cref = cref.Replace ('{', '<').Replace ('}', '>');
+
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);
+ var report = new Report (doc_module.Compiler, new NullReportPrinter ());
- Report parse_report = new Report (new NullReportPrinter ());
- var parser = new CSharpParser (seekable, source_file, parse_report);
+ var parser = new CSharpParser (seekable, source_file, report);
ParsedParameters = null;
ParsedName = null;
ParsedBuiltinType = null;
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);
// 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;
if (fne != null) {
var ns = fne as Namespace;
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;
}
}
if (ParsedParameters != null) {
+ var old_printer = mc.Module.Compiler.Report.SetPrinter (new NullReportPrinter ());
foreach (var pp in ParsedParameters) {
pp.Resolve (mc);
}
+ mc.Module.Compiler.Report.SetPrinter (old_printer);
}
if (type != null) {
xref.SetAttribute ("cref", cref);
}
- void Report419 (MemberCore mc, string member_name, MemberSpec [] mis)
- {
- Report.Warning (419, 3, mc.Location,
- "Ambiguous reference in cref attribute `{0}'. Assuming `{1}' but other overloads including `{2}' have also matched",
- member_name,
- TypeManager.GetFullNameSignature (mis [0]),
- TypeManager.GetFullNameSignature (mis [1]));
- }
-
//
// Get a prefix from member type for XML documentation (used
// to formalize cref target name).
// FIXME: with a few effort, it could be done with XmlReader,
// that means removal of DOM use.
//
- internal static void OnMethodGenerateDocComment (
- MethodCore mc, XmlElement el, Report Report)
+ void CheckParametersComments (MemberCore member, IParametersMember paramMember, XmlElement el)
{
- var paramTags = new Dictionary<string, string> ();
+ HashSet<string> found_tags = null;
foreach (XmlElement pelem in el.SelectNodes ("param")) {
string xname = pelem.GetAttribute ("name");
if (xname.Length == 0)
continue; // really? but MS looks doing so
- if (xname != "" && mc.ParameterInfo.GetParameterIndexByName (xname) < 0)
- Report.Warning (1572, 2, mc.Location, "XML comment on `{0}' has a param tag for `{1}', but there is no parameter by that name",
- mc.GetSignatureForError (), xname);
- else if (paramTags.ContainsKey (xname))
- Report.Warning (1571, 2, mc.Location, "XML comment on `{0}' has a duplicate param tag for `{1}'",
- mc.GetSignatureForError (), xname);
- paramTags [xname] = xname;
+
+ if (found_tags == null) {
+ found_tags = new HashSet<string> ();
+ }
+
+ if (xname != "" && paramMember.Parameters.GetParameterIndexByName (xname) < 0) {
+ Report.Warning (1572, 2, member.Location,
+ "XML comment on `{0}' has a param tag for `{1}', but there is no parameter by that name",
+ member.GetSignatureForError (), xname);
+ continue;
+ }
+
+ if (found_tags.Contains (xname)) {
+ Report.Warning (1571, 2, member.Location,
+ "XML comment on `{0}' has a duplicate param tag for `{1}'",
+ member.GetSignatureForError (), xname);
+ continue;
+ }
+
+ found_tags.Add (xname);
}
- IParameterData [] plist = mc.ParameterInfo.FixedParameters;
- foreach (Parameter p in plist) {
- if (paramTags.Count > 0 && !paramTags.ContainsKey (p.Name))
- Report.Warning (1573, 4, mc.Location, "Parameter `{0}' has no matching param tag in the XML comment for `{1}'",
- p.Name, mc.GetSignatureForError ());
+
+ if (found_tags != null) {
+ foreach (Parameter p in paramMember.Parameters.FixedParameters) {
+ if (!found_tags.Contains (p.Name) && !(p is ArglistParameter))
+ Report.Warning (1573, 4, member.Location,
+ "Parameter `{0}' has no matching param tag in the XML comment for `{1}'",
+ p.Name, member.GetSignatureForError ());
+ }
}
}
{
public readonly Parameter.Modifier Modifier;
public FullNamedExpression Type;
+ TypeSpec type;
public DocumentationParameter (Parameter.Modifier modifier, FullNamedExpression type)
: this (type)
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);
}
}
}