Xamarin Public Jenkins (auto-signing) 536cd135cc Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
2017-08-21 15:34:15 +00:00

420 lines
11 KiB
C#

using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
namespace Monodoc.Ecma
{
/* Some properties might not be filled/meaningful depending on kind
* like a namespace EcmaUrl won't have a valid TypeName
*/
public class EcmaDesc : IEquatable<EcmaDesc>
{
public enum Kind
{
Type,
Constructor,
Method,
Namespace,
Field,
Property,
Event,
Operator
}
public enum Mod
{
Normal,
Pointer,
Ref,
Out
}
public enum Format
{
WithArgs,
WithoutArgs
}
public Kind DescKind {
get;
set;
}
public Mod DescModifier {
get;
set;
}
public string Namespace {
get;
set;
}
public string TypeName {
get;
set;
}
public string MemberName {
get;
set;
}
public EcmaDesc NestedType {
get;
set;
}
/* A list of the array dimensions attached to this type.
* The list count corresponds to the number of recursive
* array definition (jagged arrays) the value of the
* corresponding list item is the number of dimension
* attached to that array definition instance
*/
public IList<int> ArrayDimensions {
get;
set;
}
/* Depending on the form of the url, we might not have the type
* of the argument but only how many the type/member has i.e.
* when such number is specified with a backtick
*/
public IList<EcmaDesc> GenericTypeArguments {
get;
set;
}
/* The GenericTypeArguments list may be null, in which case, this
* is an easier/safer way to check the count.
*/
public int GenericTypeArgumentsCount {
get { return GenericTypeArguments != null ? GenericTypeArguments.Count : 0; }
}
/* This property tells if the above collections only correct value
* is the number of item in it to represent generic arguments
*/
public bool GenericTypeArgumentsIsNumeric {
get {
return GenericTypeArguments != null && GenericTypeArguments.FirstOrDefault () == null;
}
}
public IList<EcmaDesc> GenericMemberArguments {
get;
set;
}
/* The GenericMemberArguments list may be null, in which case, this
* is an easier/safer way to check the count.
*/
public int GenericMemberArgumentsCount {
get { return GenericMemberArguments != null ? GenericMemberArguments.Count : 0; }
}
public bool GenericMemberArgumentsIsNumeric {
get {
return GenericMemberArguments != null && GenericMemberArguments.FirstOrDefault () == null;
}
}
public IList<EcmaDesc> MemberArguments {
get;
set;
}
/* The GenericTypeArguments list may be null, in which case, this
* is an easier/safer way to check the count.
*/
public int MemberArgumentsCount {
get { return MemberArguments != null ? MemberArguments.Count : 0; }
}
/* This indicates that we actually want an inner part of the ecmadesc
* i.e. in case of T: we could want the members (*), ctor (C), methods (M), ...
*/
public char Etc {
get;
set;
}
public bool IsEtc {
get {
return Etc != (char)0;
}
}
/* EtcFilter is only valid in some case of IsEtc when the inner part needs
* to be further filtered e.g. in case we want a listing of the type overloads
* Equals
*/
public string EtcFilter {
get;
set;
}
/* When a member is an explicit implementation of an interface member, we register
* the member EcmaDesc with its interface parent here
*/
public EcmaDesc ExplicitImplMember {
get;
set;
}
// Returns the TypeName and the generic/inner type information if existing
public string ToCompleteTypeName (char innerTypeSeparator = '.')
{
var result = TypeName;
if (GenericTypeArguments != null)
result += FormatGenericArgs (GenericTypeArguments);
if (NestedType != null)
result += innerTypeSeparator + NestedType.ToCompleteTypeName ();
if (ArrayDimensions != null && ArrayDimensions.Count > 0)
result += ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat);
return result;
}
// Returns the member name with its generic types if existing
public string ToCompleteMemberName (Format format)
{
/* We special process two cases:
* - Explicit member implementation which append a full type specification
* - Conversion operator which are exposed as normal method but have specific captioning in the end
*/
if (ExplicitImplMember != null) {
var impl = ExplicitImplMember;
return impl.FormattedNamespace + impl.ToCompleteTypeName () + "." + impl.ToCompleteMemberName (format);
} else if (format == Format.WithArgs && DescKind == Kind.Operator && MemberName.EndsWith ("Conversion")) {
var type1 = MemberArguments[0].FormattedNamespace + MemberArguments[0].ToCompleteTypeName () + ModToString (MemberArguments[0]);
var type2 = MemberArguments[1].FormattedNamespace + MemberArguments[1].ToCompleteTypeName () + ModToString (MemberArguments[1]);
return type1 + " to " + type2;
}
var result = IsEtc && !string.IsNullOrEmpty (EtcFilter) ? EtcFilter : MemberName;
// Temporary hack for monodoc produced inner type ctor
//if (DescKind == Kind.Constructor && NestedType != null)
//result = ToCompleteTypeName ();
if (GenericMemberArguments != null)
result += FormatGenericArgs (GenericMemberArguments);
if (format == Format.WithArgs) {
result += '(';
if (MemberArguments != null && MemberArguments.Count > 0) {
var args = MemberArguments.Select (a => FormatNamespace (a) + a.ToCompleteTypeName ('+') + ModToString (a));
result += string.Join (",", args);
}
result += ')';
}
return result;
}
public string ToEcmaCref ()
{
var sb = new StringBuilder ();
// Cref type
sb.Append (DescKind.ToString ()[0]);
sb.Append (":");
// Create the rest
ConstructCRef (sb);
return sb.ToString ();
}
void ConstructCRef (StringBuilder sb, bool skipLeadingDot = false)
{
if (string.IsNullOrEmpty (Namespace))
skipLeadingDot = true;
sb.Append (Namespace);
if (DescKind == Kind.Namespace)
return;
if (!skipLeadingDot)
sb.Append ('.');
sb.Append (TypeName);
AppendGenericArguments (sb, GenericTypeArguments, GenericTypeArgumentsIsNumeric, GenericTypeArgumentsCount);
if (NestedType != null) {
sb.Append ('+');
NestedType.ConstructCRef (sb, skipLeadingDot: true);
}
if (ArrayDimensions != null && ArrayDimensions.Count > 0) {
for (int i = 0; i < ArrayDimensions.Count; i++) {
sb.Append ('[');
sb.Append (new string (',', ArrayDimensions[i] - 1));
sb.Append (']');
}
}
if (DescKind == Kind.Type)
return;
if (ExplicitImplMember != null) {
sb.Append ('$');
ExplicitImplMember.DescKind = this.DescKind;
ExplicitImplMember.ConstructCRef (sb, skipLeadingDot: false);
return;
}
sb.Append (".");
sb.Append (MemberName);
AppendGenericArguments (sb, GenericMemberArguments, GenericMemberArgumentsIsNumeric, GenericMemberArgumentsCount);
if (MemberArguments != null && MemberArgumentsCount > 0) {
sb.Append ("(");
int i=0;
foreach (var a in MemberArguments) {
if (i > 0) {
sb.Append(",");
}
a.ConstructCRef (sb);
i++;
}
sb.Append (")");
}
}
void AppendGenericArguments (StringBuilder sb, IEnumerable<EcmaDesc> arguments, bool isNumeric, int argumentsCount)
{
if (arguments != null && isNumeric) {
sb.AppendFormat ("`{0}", argumentsCount);
} else if (arguments != null) {
sb.Append ('<');
int i=0;
foreach (var t in arguments) {
if (i > 0) {
sb.Append (",");
}
t.ConstructCRef (sb);
i++;
}
sb.Append ('>');
}
}
public override string ToString ()
{
return string.Format ("({8}) {0}::{1}{2}{3}{7} {4}{5}{6} {9} {10}",
Namespace,
TypeName,
FormatGenericArgsFull (GenericTypeArguments),
NestedType != null ? "+" + NestedType.ToString () : string.Empty,
MemberName ?? string.Empty,
FormatGenericArgsFull (GenericMemberArguments),
MemberArguments != null ? "(" + string.Join (",", MemberArguments.Select (m => m.ToString ())) + ")" : string.Empty,
ArrayDimensions != null && ArrayDimensions.Count > 0 ? ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat) : string.Empty,
DescKind.ToString ()[0],
Etc != 0 ? '(' + Etc.ToString () + ')' : string.Empty,
ExplicitImplMember != null ? "$" + ExplicitImplMember.ToString () : string.Empty);
}
public override bool Equals (object other)
{
var otherDesc = other as EcmaDesc;
return otherDesc != null && Equals (otherDesc);
}
public bool Equals (EcmaDesc other)
{
if (other == null)
return false;
if (NestedType == null ^ other.NestedType == null
|| ArrayDimensions == null ^ other.ArrayDimensions == null
|| GenericTypeArguments == null ^ other.GenericTypeArguments == null
|| GenericMemberArguments == null ^ other.GenericMemberArguments == null
|| MemberArguments == null ^ other.MemberArguments == null
|| ExplicitImplMember == null ^ other.ExplicitImplMember == null)
return false;
return other != null
&& DescKind == other.DescKind
&& TypeName == other.TypeName
&& Namespace == other.Namespace
&& MemberName == other.MemberName
&& (NestedType == null || NestedType.Equals (other.NestedType))
&& (ArrayDimensions == null || ArrayDimensions.SequenceEqual (other.ArrayDimensions))
&& (GenericTypeArguments == null || GenericTypeArguments.SequenceEqual (other.GenericTypeArguments))
&& (GenericMemberArguments == null || GenericMemberArguments.SequenceEqual (other.GenericMemberArguments))
&& (MemberArguments == null || MemberArguments.SequenceEqual (other.MemberArguments))
&& Etc == other.Etc
&& EtcFilter == other.EtcFilter
&& (ExplicitImplMember == null || ExplicitImplMember.Equals (other.ExplicitImplMember));
}
public override int GetHashCode ()
{
return DescKind.GetHashCode ()
^ TypeName.GetHashCode ()
^ Namespace.GetHashCode ()
^ MemberName.GetHashCode ();
}
bool What (bool input)
{
if (!input)
throw new Exception ("Not equal");
return input;
}
bool WhatT (bool input)
{
if (input)
throw new Exception ("Not equal");
return input;
}
string FormatNamespace (EcmaDesc desc)
{
return string.IsNullOrEmpty (desc.Namespace) ? string.Empty : desc.Namespace + ".";
}
string FormatGenericArgs (IEnumerable<EcmaDesc> args)
{
if (args == null || !args.Any ())
return string.Empty;
// If we only have the number of generic arguments, use ` notation
if (args.First () == null)
return "`" + args.Count ();
IEnumerable<string> argsList = args.Select (t => FormatNamespace (t) + t.ToCompleteTypeName ());
return "<" + string.Join (",", argsList) + ">";
}
string FormatGenericArgsFull (IEnumerable<EcmaDesc> genericArgs)
{
return genericArgs != null ? "<" + string.Join (",", genericArgs.Select (t => t.ToString ())) + ">" : string.Empty;
}
string ModToString (EcmaDesc desc)
{
switch (desc.DescModifier) {
case Mod.Pointer:
return "*";
case Mod.Ref:
return "&";
case Mod.Out:
return "@";
default:
return string.Empty;
}
}
string FormattedNamespace {
get {
return !string.IsNullOrEmpty (Namespace) ? Namespace + "." : string.Empty;
}
}
}
}