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 /* This property tells if the above collections only correct value
90 * is the number of item in it to represent generic arguments
92 public bool GenericTypeArgumentsIsNumeric {
94 return GenericTypeArguments != null && GenericTypeArguments.FirstOrDefault () == null;
98 public IList<EcmaDesc> GenericMemberArguments {
103 public bool GenericMemberArgumentsIsNumeric {
105 return GenericMemberArguments != null && GenericMemberArguments.FirstOrDefault () == null;
109 public IList<EcmaDesc> MemberArguments {
114 /* This indicates that we actually want an inner part of the ecmadesc
115 * i.e. in case of T: we could want the members (*), ctor (C), methods (M), ...
124 return Etc != (char)0;
128 /* EtcFilter is only valid in some case of IsEtc when the inner part needs
129 * to be further filtered e.g. in case we want a listing of the type overloads
132 public string EtcFilter {
137 /* When a member is an explicit implementation of an interface member, we register
138 * the member EcmaDesc with its interface parent here
140 public EcmaDesc ExplicitImplMember {
145 // Returns the TypeName and the generic/inner type information if existing
146 public string ToCompleteTypeName (char innerTypeSeparator = '.')
148 var result = TypeName;
149 if (GenericTypeArguments != null)
150 result += FormatGenericArgs (GenericTypeArguments);
151 if (NestedType != null)
152 result += innerTypeSeparator + NestedType.ToCompleteTypeName ();
153 if (ArrayDimensions != null && ArrayDimensions.Count > 0)
154 result += ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat);
159 // Returns the member name with its generic types if existing
160 public string ToCompleteMemberName (Format format)
162 /* We special process two cases:
163 * - Explicit member implementation which append a full type specification
164 * - Conversion operator which are exposed as normal method but have specific captioning in the end
166 if (ExplicitImplMember != null) {
167 var impl = ExplicitImplMember;
168 return impl.FormattedNamespace + impl.ToCompleteTypeName () + "." + impl.ToCompleteMemberName (format);
169 } else if (format == Format.WithArgs && DescKind == Kind.Operator && MemberName.EndsWith ("Conversion")) {
170 var type1 = MemberArguments[0].FormattedNamespace + MemberArguments[0].ToCompleteTypeName () + ModToString (MemberArguments[0]);
171 var type2 = MemberArguments[1].FormattedNamespace + MemberArguments[1].ToCompleteTypeName () + ModToString (MemberArguments[1]);
172 return type1 + " to " + type2;
175 var result = IsEtc && !string.IsNullOrEmpty (EtcFilter) ? EtcFilter : MemberName;
177 // Temporary hack for monodoc produced inner type ctor
178 //if (DescKind == Kind.Constructor && NestedType != null)
179 //result = ToCompleteTypeName ();
181 if (GenericMemberArguments != null)
182 result += FormatGenericArgs (GenericMemberArguments);
184 if (format == Format.WithArgs) {
186 if (MemberArguments != null && MemberArguments.Count > 0) {
187 var args = MemberArguments.Select (a => FormatNamespace (a) + a.ToCompleteTypeName ('+') + ModToString (a));
188 result += string.Join (",", args);
196 public string ToEcmaCref ()
198 var sb = new StringBuilder ();
200 sb.Append (DescKind.ToString ()[0]);
204 return sb.ToString ();
207 void ConstructCRef (StringBuilder sb)
209 sb.Append (Namespace);
210 if (DescKind == Kind.Namespace)
214 sb.Append (TypeName);
215 if (GenericTypeArguments != null) {
217 foreach (var t in GenericTypeArguments)
218 t.ConstructCRef (sb);
221 if (NestedType != null) {
223 NestedType.ConstructCRef (sb);
225 if (ArrayDimensions != null && ArrayDimensions.Count > 0) {
226 for (int i = 0; i < ArrayDimensions.Count; i++) {
228 sb.Append (new string (',', ArrayDimensions[i] - 1));
232 if (DescKind == Kind.Type)
235 if (MemberArguments != null) {
240 public override string ToString ()
242 return string.Format ("({8}) {0}::{1}{2}{3}{7} {4}{5}{6} {9} {10}",
245 FormatGenericArgsFull (GenericTypeArguments),
246 NestedType != null ? "+" + NestedType.ToString () : string.Empty,
247 MemberName ?? string.Empty,
248 FormatGenericArgsFull (GenericMemberArguments),
249 MemberArguments != null ? "(" + string.Join (",", MemberArguments.Select (m => m.ToString ())) + ")" : string.Empty,
250 ArrayDimensions != null && ArrayDimensions.Count > 0 ? ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat) : string.Empty,
251 DescKind.ToString ()[0],
252 Etc != 0 ? '(' + Etc.ToString () + ')' : string.Empty,
253 ExplicitImplMember != null ? "$" + ExplicitImplMember.ToString () : string.Empty);
257 public override bool Equals (object other)
259 var otherDesc = other as EcmaDesc;
260 return otherDesc != null && Equals (otherDesc);
263 public bool Equals (EcmaDesc other)
268 if (NestedType == null ^ other.NestedType == null
269 || ArrayDimensions == null ^ other.ArrayDimensions == null
270 || GenericTypeArguments == null ^ other.GenericTypeArguments == null
271 || GenericMemberArguments == null ^ other.GenericMemberArguments == null
272 || MemberArguments == null ^ other.MemberArguments == null
273 || ExplicitImplMember == null ^ other.ExplicitImplMember == null)
277 && DescKind == other.DescKind
278 && TypeName == other.TypeName
279 && Namespace == other.Namespace
280 && MemberName == other.MemberName
281 && (NestedType == null || NestedType.Equals (other.NestedType))
282 && (ArrayDimensions == null || ArrayDimensions.SequenceEqual (other.ArrayDimensions))
283 && (GenericTypeArguments == null || GenericTypeArguments.SequenceEqual (other.GenericTypeArguments))
284 && (GenericMemberArguments == null || GenericMemberArguments.SequenceEqual (other.GenericMemberArguments))
285 && (MemberArguments == null || MemberArguments.SequenceEqual (other.MemberArguments))
287 && EtcFilter == other.EtcFilter
288 && (ExplicitImplMember == null || ExplicitImplMember.Equals (other.ExplicitImplMember));
291 public override int GetHashCode ()
293 return DescKind.GetHashCode ()
294 ^ TypeName.GetHashCode ()
295 ^ Namespace.GetHashCode ()
296 ^ MemberName.GetHashCode ();
299 bool What (bool input)
302 throw new Exception ("Not equal");
306 bool WhatT (bool input)
309 throw new Exception ("Not equal");
313 string FormatNamespace (EcmaDesc desc)
315 return string.IsNullOrEmpty (desc.Namespace) ? string.Empty : desc.Namespace + ".";
318 string FormatGenericArgs (IEnumerable<EcmaDesc> args)
320 if (args == null || !args.Any ())
323 IEnumerable<string> argsList = null;
325 // HACK: If we don't have fully specified EcmaDesc for generic arguments
326 // we use the most common names for the argument length configuration
327 if (args.Any (a => a == null)) {
328 var argCount = args.Count ();
331 argsList = new string[] { "T" };
334 argsList = new string[] { "TKey", "TValue" };
337 argsList = Enumerable.Range (1, argCount).Select (i => "T" + i);
341 argsList = args.Select (t => FormatNamespace (t) + t.ToCompleteTypeName ());
344 return "<" + string.Join (",", argsList) + ">";
347 string FormatGenericArgsFull (IEnumerable<EcmaDesc> genericArgs)
349 return genericArgs != null ? "<" + string.Join (",", genericArgs.Select (t => t.ToString ())) + ">" : string.Empty;
352 string ModToString (EcmaDesc desc)
354 switch (desc.DescModifier) {
366 string FormattedNamespace {
368 return !string.IsNullOrEmpty (Namespace) ? Namespace + "." : string.Empty;