4 using System.Collections.Generic;
8 /* Some properties might not be filled/meaningful depending on kind
9 * like a namespace EcmaUrl won't have a valid TypeName
11 public class EcmaDesc : IEquatable<EcmaDesc>
39 public Kind DescKind {
44 public Mod DescModifier {
49 public string Namespace {
54 public string TypeName {
59 public string MemberName {
64 public EcmaDesc NestedType {
69 /* A list of the array dimensions attached to this type.
70 * The list count corresponds to the number of recursive
71 * array definition (jagged arrays) the value of the
72 * corresponding list item is the number of dimension
73 * attached to that array definition instance
75 public IList<int> ArrayDimensions {
80 /* Depending on the form of the url, we might not have the type
81 * of the argument but only how many the type/member has i.e.
82 * when such number is specified with a backtick
84 public IList<EcmaDesc> GenericTypeArguments {
89 /* The GenericTypeArguments list may be null, in which case, this
90 * is an easier/safer way to check the count.
92 public int GenericTypeArgumentsCount {
93 get { return GenericTypeArguments != null ? GenericTypeArguments.Count : 0; }
96 /* This property tells if the above collections only correct value
97 * is the number of item in it to represent generic arguments
99 public bool GenericTypeArgumentsIsNumeric {
101 return GenericTypeArguments != null && GenericTypeArguments.FirstOrDefault () == null;
105 public IList<EcmaDesc> GenericMemberArguments {
110 /* The GenericMemberArguments list may be null, in which case, this
111 * is an easier/safer way to check the count.
113 public int GenericMemberArgumentsCount {
114 get { return GenericMemberArguments != null ? GenericMemberArguments.Count : 0; }
117 public bool GenericMemberArgumentsIsNumeric {
119 return GenericMemberArguments != null && GenericMemberArguments.FirstOrDefault () == null;
123 public IList<EcmaDesc> MemberArguments {
128 /* The GenericTypeArguments list may be null, in which case, this
129 * is an easier/safer way to check the count.
131 public int MemberArgumentsCount {
132 get { return MemberArguments != null ? MemberArguments.Count : 0; }
135 /* This indicates that we actually want an inner part of the ecmadesc
136 * i.e. in case of T: we could want the members (*), ctor (C), methods (M), ...
145 return Etc != (char)0;
149 /* EtcFilter is only valid in some case of IsEtc when the inner part needs
150 * to be further filtered e.g. in case we want a listing of the type overloads
153 public string EtcFilter {
158 /* When a member is an explicit implementation of an interface member, we register
159 * the member EcmaDesc with its interface parent here
161 public EcmaDesc ExplicitImplMember {
166 // Returns the TypeName and the generic/inner type information if existing
167 public string ToCompleteTypeName (char innerTypeSeparator = '.')
169 var result = TypeName;
170 if (GenericTypeArguments != null)
171 result += FormatGenericArgs (GenericTypeArguments);
172 if (NestedType != null)
173 result += innerTypeSeparator + NestedType.ToCompleteTypeName ();
174 if (ArrayDimensions != null && ArrayDimensions.Count > 0)
175 result += ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat);
180 // Returns the member name with its generic types if existing
181 public string ToCompleteMemberName (Format format)
183 /* We special process two cases:
184 * - Explicit member implementation which append a full type specification
185 * - Conversion operator which are exposed as normal method but have specific captioning in the end
187 if (ExplicitImplMember != null) {
188 var impl = ExplicitImplMember;
189 return impl.FormattedNamespace + impl.ToCompleteTypeName () + "." + impl.ToCompleteMemberName (format);
190 } else if (format == Format.WithArgs && DescKind == Kind.Operator && MemberName.EndsWith ("Conversion")) {
191 var type1 = MemberArguments[0].FormattedNamespace + MemberArguments[0].ToCompleteTypeName () + ModToString (MemberArguments[0]);
192 var type2 = MemberArguments[1].FormattedNamespace + MemberArguments[1].ToCompleteTypeName () + ModToString (MemberArguments[1]);
193 return type1 + " to " + type2;
196 var result = IsEtc && !string.IsNullOrEmpty (EtcFilter) ? EtcFilter : MemberName;
198 // Temporary hack for monodoc produced inner type ctor
199 //if (DescKind == Kind.Constructor && NestedType != null)
200 //result = ToCompleteTypeName ();
202 if (GenericMemberArguments != null)
203 result += FormatGenericArgs (GenericMemberArguments);
205 if (format == Format.WithArgs) {
207 if (MemberArguments != null && MemberArguments.Count > 0) {
208 var args = MemberArguments.Select (a => FormatNamespace (a) + a.ToCompleteTypeName ('+') + ModToString (a));
209 result += string.Join (",", args);
217 public string ToEcmaCref ()
219 var sb = new StringBuilder ();
221 sb.Append (DescKind.ToString ()[0]);
226 return sb.ToString ();
229 void ConstructCRef (StringBuilder sb)
231 sb.Append (Namespace);
232 if (DescKind == Kind.Namespace)
236 sb.Append (TypeName);
237 if (GenericTypeArguments != null) {
240 foreach (var t in GenericTypeArguments) {
244 t.ConstructCRef (sb);
250 if (NestedType != null) {
252 NestedType.ConstructCRef (sb);
254 if (ArrayDimensions != null && ArrayDimensions.Count > 0) {
255 for (int i = 0; i < ArrayDimensions.Count; i++) {
257 sb.Append (new string (',', ArrayDimensions[i] - 1));
261 if (DescKind == Kind.Type)
265 sb.Append (MemberName);
267 if (MemberArguments != null && MemberArgumentsCount > 0) {
270 foreach (var a in MemberArguments) {
274 a.ConstructCRef (sb);
281 public override string ToString ()
283 return string.Format ("({8}) {0}::{1}{2}{3}{7} {4}{5}{6} {9} {10}",
286 FormatGenericArgsFull (GenericTypeArguments),
287 NestedType != null ? "+" + NestedType.ToString () : string.Empty,
288 MemberName ?? string.Empty,
289 FormatGenericArgsFull (GenericMemberArguments),
290 MemberArguments != null ? "(" + string.Join (",", MemberArguments.Select (m => m.ToString ())) + ")" : string.Empty,
291 ArrayDimensions != null && ArrayDimensions.Count > 0 ? ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat) : string.Empty,
292 DescKind.ToString ()[0],
293 Etc != 0 ? '(' + Etc.ToString () + ')' : string.Empty,
294 ExplicitImplMember != null ? "$" + ExplicitImplMember.ToString () : string.Empty);
298 public override bool Equals (object other)
300 var otherDesc = other as EcmaDesc;
301 return otherDesc != null && Equals (otherDesc);
304 public bool Equals (EcmaDesc other)
309 if (NestedType == null ^ other.NestedType == null
310 || ArrayDimensions == null ^ other.ArrayDimensions == null
311 || GenericTypeArguments == null ^ other.GenericTypeArguments == null
312 || GenericMemberArguments == null ^ other.GenericMemberArguments == null
313 || MemberArguments == null ^ other.MemberArguments == null
314 || ExplicitImplMember == null ^ other.ExplicitImplMember == null)
318 && DescKind == other.DescKind
319 && TypeName == other.TypeName
320 && Namespace == other.Namespace
321 && MemberName == other.MemberName
322 && (NestedType == null || NestedType.Equals (other.NestedType))
323 && (ArrayDimensions == null || ArrayDimensions.SequenceEqual (other.ArrayDimensions))
324 && (GenericTypeArguments == null || GenericTypeArguments.SequenceEqual (other.GenericTypeArguments))
325 && (GenericMemberArguments == null || GenericMemberArguments.SequenceEqual (other.GenericMemberArguments))
326 && (MemberArguments == null || MemberArguments.SequenceEqual (other.MemberArguments))
328 && EtcFilter == other.EtcFilter
329 && (ExplicitImplMember == null || ExplicitImplMember.Equals (other.ExplicitImplMember));
332 public override int GetHashCode ()
334 return DescKind.GetHashCode ()
335 ^ TypeName.GetHashCode ()
336 ^ Namespace.GetHashCode ()
337 ^ MemberName.GetHashCode ();
340 bool What (bool input)
343 throw new Exception ("Not equal");
347 bool WhatT (bool input)
350 throw new Exception ("Not equal");
354 string FormatNamespace (EcmaDesc desc)
356 return string.IsNullOrEmpty (desc.Namespace) ? string.Empty : desc.Namespace + ".";
359 string FormatGenericArgs (IEnumerable<EcmaDesc> args)
361 if (args == null || !args.Any ())
363 // If we only have the number of generic arguments, use ` notation
364 if (args.First () == null)
365 return "`" + args.Count ();
367 IEnumerable<string> argsList = args.Select (t => FormatNamespace (t) + t.ToCompleteTypeName ());
369 return "<" + string.Join (",", argsList) + ">";
372 string FormatGenericArgsFull (IEnumerable<EcmaDesc> genericArgs)
374 return genericArgs != null ? "<" + string.Join (",", genericArgs.Select (t => t.ToString ())) + ">" : string.Empty;
377 string ModToString (EcmaDesc desc)
379 switch (desc.DescModifier) {
391 string FormattedNamespace {
393 return !string.IsNullOrEmpty (Namespace) ? Namespace + "." : string.Empty;