//
// Processes "see" or "seealso" elements from cref attribute.
//
void HandleXrefCommon(MemberCore mc, XmlElement xref)
{
string cref = xref.GetAttribute("cref");
// when, XmlReader, "if (cref == null)"
if (!xref.HasAttribute("cref"))
{
return;
}
// Nothing to be resolved the reference is marked explicitly
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));
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
}
}
;
SeekableStreamReader seekable = new SeekableStreamReader(s, encoding, session.StreamReaderBuffer);
var parser = new CSharpParser(seekable, source_file, report, session);
ParsedParameters = null;
ParsedName = null;
ParsedBuiltinType = null;
ParsedOperator = null;
parser.Lexer.putback_char = Tokenizer.DocumentationXref;
parser.Lexer.parsing_generic_declaration_doc = true;
parser.parse();
if (report.Errors > 0)
{
Report.Warning(1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
mc.GetSignatureForError(), cref);
xref.SetAttribute("cref", "!:" + cref);
return;
}
MemberSpec member;
string prefix = null;
FullNamedExpression fne = null;
//
// Try built-in type first because we are using ParsedName as identifier of
// member names on built-in types
//
if (ParsedBuiltinType != null && (ParsedParameters == null || ParsedName != null))
{
member = ParsedBuiltinType.Type;
}
else
{
member = null;
}
if (ParsedName != null || ParsedOperator.HasValue)
{
TypeSpec type = null;
string member_name = null;
if (member == null)
{
if (ParsedOperator.HasValue)
{
type = mc.CurrentType;
}
else if (ParsedName.Left != null)
{
fne = ResolveMemberName(mc, ParsedName.Left);
if (fne != null)
{
var ns = fne as NamespaceExpression;
if (ns != null)
{
fne = ns.LookupTypeOrNamespace(mc, ParsedName.Name, ParsedName.Arity, LookupMode.Probing, Location.Null);
if (fne != null)
{
member = fne.Type;
}
}
else
{
type = fne.Type;
}
}
}
else
{
fne = ResolveMemberName(mc, ParsedName);
if (fne == null)
{
type = mc.CurrentType;
}
else if (ParsedParameters == null)
{
member = fne.Type;
}
else if (fne.Type.MemberDefinition == mc.CurrentType.MemberDefinition)
{
member_name = Constructor.ConstructorName;
type = fne.Type;
}
}
}
else
{
type = (TypeSpec)member;
member = null;
}
if (ParsedParameters != null)
{
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);
}
}
if (type != null)
{
if (member_name == null)
{
member_name = ParsedOperator.HasValue ?
Operator.GetMetadataName(ParsedOperator.Value) : ParsedName.Name;
}
int parsed_param_count;
if (ParsedOperator == Operator.OpType.Explicit || ParsedOperator == Operator.OpType.Implicit)
{
parsed_param_count = ParsedParameters.Count - 1;
}
else if (ParsedParameters != null)
{
parsed_param_count = ParsedParameters.Count;
}
else
{
parsed_param_count = 0;
}
int parameters_match = -1;
do
{
var members = MemberCache.FindMembers(type, member_name, true);
if (members != null)
{
foreach (var m in members)
{
if (ParsedName != null && m.Arity != ParsedName.Arity)
{
continue;
}
if (ParsedParameters != null)
{
IParametersMember pm = m as IParametersMember;
if (pm == null)
{
continue;
}
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_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;
}
i = -1;
break;
}
}
if (i < 0)
{
continue;
}
if (ParsedOperator == Operator.OpType.Explicit || ParsedOperator == Operator.OpType.Implicit)
{
if (pm.MemberType != ParsedParameters[parsed_param_count].TypeSpec)
{
parameters_match = parsed_param_count + 1;
continue;
}
}
else
{
if (parsed_param_count != pm_params.Count)
{
continue;
}
}
}
if (member != null)
{
Report.Warning(419, 3, mc.Location,
"Ambiguous reference in cref attribute `{0}'. Assuming `{1}' but other overloads including `{2}' have also matched",
cref, member.GetSignatureForError(), m.GetSignatureForError());
break;
}
member = m;
}
}
// Continue with parent type for nested types
if (member == null)
{
type = type.DeclaringType;
}
else
{
type = null;
}
} while (type != null);
if (member == null && parameters_match >= 0)
{
for (int i = parameters_match; i < parsed_param_count; ++i)
{
Report.Warning(1580, 1, mc.Location, "Invalid type for parameter `{0}' in XML comment cref attribute `{1}'",
(i + 1).ToString(), cref);
}
if (parameters_match == parsed_param_count + 1)
{
Report.Warning(1581, 1, mc.Location, "Invalid return type in XML comment cref attribute `{0}'", cref);
}
}
}
}
if (member == null)
{
Report.Warning(1574, 1, mc.Location, "XML comment on `{0}' has cref attribute `{1}' that could not be resolved",
mc.GetSignatureForError(), cref);
cref = "!:" + cref;
}
else if (member == InternalType.Namespace)
{
cref = "N:" + fne.GetSignatureForError();
}
else
{
prefix = GetMemberDocHead(member);
cref = prefix + member.GetSignatureForDocumentation();
}
xref.SetAttribute("cref", cref);
}