private static void HandleXrefCommon (MemberCore mc,
DeclSpace ds, XmlElement xref, Report Report)
{
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 parameters; // method parameter list
// When it found '?:' ('T:' 'M:' 'F:' 'P:' 'E:' etc.),
// MS ignores not only its member kind, but also
// the entire syntax correctness. Nor it also does
// type fullname resolution i.e. "T:List(int)" is kept
// as T:List(int), not
// T:System.Collections.Generic.List<System.Int32>
if (cref.Length > 2 && cref [1] == ':')
return;
else
signature = cref;
// Also note that without "T:" any generic type
// indication fails.
int parens_pos = signature.IndexOf ('(');
int brace_pos = parens_pos >= 0 ? -1 :
signature.IndexOf ('[');
if (parens_pos > 0 && signature [signature.Length - 1] == ')') {
name = signature.Substring (0, parens_pos).Trim (wsChars);
parameters = signature.Substring (parens_pos + 1, signature.Length - parens_pos - 2).Trim (wsChars);
}
else if (brace_pos > 0 && signature [signature.Length - 1] == ']') {
name = signature.Substring (0, brace_pos).Trim (wsChars);
parameters = signature.Substring (brace_pos + 1, signature.Length - brace_pos - 2).Trim (wsChars);
}
else {
name = signature;
parameters = null;
}
Normalize (mc, ref name, Report);
string identifier = GetBodyIdentifierFromName (name);
// Check if identifier is valid.
// This check is not necessary to mark as error, but
// csc specially reports CS1584 for wrong identifiers.
string [] name_elems = identifier.Split ('.');
for (int i = 0; i < name_elems.Length; i++) {
string nameElem = GetBodyIdentifierFromName (name_elems [i]);
if (i > 0)
Normalize (mc, ref nameElem, Report);
if (!Tokenizer.IsValidIdentifier (nameElem)
&& nameElem.IndexOf ("operator") < 0) {
Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
mc.GetSignatureForError (), cref);
xref.SetAttribute ("cref", "!:" + signature);
return;
}
}
// check if parameters are valid
AParametersCollection parameter_types;
if (parameters == null)
parameter_types = null;
else if (parameters.Length == 0)
parameter_types = ParametersCompiled.EmptyReadOnlyParameters;
else {
string [] param_list = parameters.Split (',');
var plist = new List<TypeSpec> ();
for (int i = 0; i < param_list.Length; i++) {
string param_type_name = param_list [i].Trim (wsChars);
Normalize (mc, ref param_type_name, Report);
TypeSpec param_type = FindDocumentedType (mc, param_type_name, ds, cref, Report);
if (param_type == null) {
Report.Warning (1580, 1, mc.Location, "Invalid type for parameter `{0}' in XML comment cref attribute `{1}'",
(i + 1).ToString (), cref);
return;
}
plist.Add (param_type);
}
parameter_types = ParametersCompiled.CreateFullyResolved (plist.ToArray ());
}
TypeSpec type = FindDocumentedType (mc, name, ds, cref, Report);
if (type != null
// delegate must not be referenced with args
&& (!type.IsDelegate
|| parameter_types == null)) {
string result = GetSignatureForDoc (type)
+ (brace_pos < 0 ? String.Empty : signature.Substring (brace_pos));
xref.SetAttribute ("cref", "T:" + result);
return; // a type
}
int period = name.LastIndexOf ('.');
if (period > 0) {
string typeName = name.Substring (0, period);
string member_name = name.Substring (period + 1);
string lookup_name = member_name == "this" ? MemberCache.IndexerNameAlias : member_name;
Normalize (mc, ref lookup_name, Report);
Normalize (mc, ref member_name, Report);
type = FindDocumentedType (mc, typeName, ds, cref, Report);
int warn_result;
if (type != null) {
var mi = FindDocumentedMember (mc, type, lookup_name, parameter_types, ds, out warn_result, cref, true, name, Report);
if (warn_result > 0)
return;
if (mi != null) {
// we cannot use 'type' directly
// to get its name, since mi
// could be from DeclaringType
// for nested types.
xref.SetAttribute ("cref", GetMemberDocHead (mi) + GetSignatureForDoc (mi.DeclaringType) + "." + member_name + GetParametersFormatted (mi));
return; // a member of a type
}
}
} else {
int warn_result;
var mi = FindDocumentedMember (mc, ds.PartialContainer.Definition, name, parameter_types, ds, out warn_result, cref, true, name, Report);
if (warn_result > 0)
return;
if (mi != null) {
// we cannot use 'type' directly
// to get its name, since mi
// could be from DeclaringType
// for nested types.
xref.SetAttribute ("cref", GetMemberDocHead (mi) + GetSignatureForDoc (mi.DeclaringType) + "." + name + GetParametersFormatted (mi));
return; // local member name
}
}
// It still might be part of namespace name.
Namespace ns = ds.NamespaceEntry.NS.GetNamespace (name, false);
if (ns != null) {
xref.SetAttribute ("cref", "N:" + ns.GetSignatureForError ());
return; // a namespace
}
if (mc.Module.GlobalRootNamespace.IsNamespace (name)) {
xref.SetAttribute ("cref", "N:" + name);
return; // a namespace
}
Report.Warning (1574, 1, mc.Location, "XML comment on `{0}' has cref attribute `{1}' that could not be resolved",
mc.GetSignatureForError (), cref);
xref.SetAttribute ("cref", "!:" + name);
}