Added/modified tests for marshalling and remoting of referencesource StringBuilder...
[mono.git] / mcs / class / monodoc / Monodoc.Ecma / EcmaDesc.cs
1 using System;
2 using System.Linq;
3 using System.Text;
4 using System.Collections.Generic;
5
6 namespace Monodoc.Ecma
7 {
8         /* Some properties might not be filled/meaningful depending on kind
9          * like a namespace EcmaUrl won't have a valid TypeName
10          */
11         public class EcmaDesc : IEquatable<EcmaDesc>
12         {
13                 public enum Kind
14                 {
15                         Type,
16                         Constructor,
17                         Method,
18                         Namespace,
19                         Field,
20                         Property,
21                         Event,
22                         Operator
23                 }
24
25                 public enum Mod
26                 {
27                         Normal,
28                         Pointer,
29                         Ref,
30                         Out
31                 }
32
33                 public enum Format
34                 {
35                         WithArgs,
36                         WithoutArgs
37                 }
38
39                 public Kind DescKind {
40                         get;
41                         set;
42                 }
43
44                 public Mod DescModifier {
45                         get;
46                         set;
47                 }
48
49                 public string Namespace {
50                         get;
51                         set;
52                 }
53
54                 public string TypeName {
55                         get;
56                         set;
57                 }
58
59                 public string MemberName {
60                         get;
61                         set;
62                 }
63
64                 public EcmaDesc NestedType {
65                         get;
66                         set;
67                 }
68
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
74                  */
75                 public IList<int> ArrayDimensions {
76                         get;
77                         set;
78                 }
79
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
83                  */
84                 public IList<EcmaDesc> GenericTypeArguments {
85                         get;
86                         set;
87                 }
88
89                 /* The GenericTypeArguments list may be null, in which case, this
90                  * is an easier/safer way to check the count.
91                  */
92                 public int GenericTypeArgumentsCount {
93                         get { return GenericTypeArguments != null ? GenericTypeArguments.Count : 0; }
94                 }
95
96                 /* This property tells if the above collections only correct value
97                  * is the number of item in it to represent generic arguments
98                  */
99                 public bool GenericTypeArgumentsIsNumeric {
100                         get {
101                                 return GenericTypeArguments != null && GenericTypeArguments.FirstOrDefault () == null;
102                         }
103                 }
104
105                 public IList<EcmaDesc> GenericMemberArguments {
106                         get;
107                         set;
108                 }
109
110                 /* The GenericMemberArguments list may be null, in which case, this
111                  * is an easier/safer way to check the count.
112                  */
113                 public int GenericMemberArgumentsCount {
114                         get { return GenericMemberArguments != null ? GenericMemberArguments.Count : 0; }
115                 }
116
117                 public bool GenericMemberArgumentsIsNumeric {
118                         get {
119                                 return GenericMemberArguments != null && GenericMemberArguments.FirstOrDefault () == null;
120                         }
121                 }
122
123                 public IList<EcmaDesc> MemberArguments {
124                         get;
125                         set;
126                 }
127
128                 /* The GenericTypeArguments list may be null, in which case, this
129                  * is an easier/safer way to check the count.
130                  */
131                 public int MemberArgumentsCount {
132                         get { return MemberArguments != null ? MemberArguments.Count : 0; }
133                 }
134
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), ...
137                  */
138                 public char Etc {
139                         get;
140                         set;
141                 }
142
143                 public bool IsEtc {
144                         get {
145                                 return Etc != (char)0;
146                         }
147                 }
148
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
151                  * Equals
152                  */
153                 public string EtcFilter {
154                         get;
155                         set;
156                 }
157
158                 /* When a member is an explicit implementation of an interface member, we register
159                  * the member EcmaDesc with its interface parent here
160                  */
161                 public EcmaDesc ExplicitImplMember {
162                         get;
163                         set;
164                 }
165
166                 // Returns the TypeName and the generic/inner type information if existing
167                 public string ToCompleteTypeName (char innerTypeSeparator = '.')
168                 {
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);
176
177                         return result;
178                 }
179
180                 // Returns the member name with its generic types if existing
181                 public string ToCompleteMemberName (Format format)
182                 {
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
186                          */
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;
194                         }
195
196                         var result = IsEtc && !string.IsNullOrEmpty (EtcFilter) ? EtcFilter : MemberName;
197
198                         // Temporary hack for monodoc produced inner type ctor
199                         //if (DescKind == Kind.Constructor && NestedType != null)
200                                 //result = ToCompleteTypeName ();
201
202                         if (GenericMemberArguments != null)
203                                 result += FormatGenericArgs (GenericMemberArguments);
204
205                         if (format == Format.WithArgs) {
206                                 result += '(';
207                                 if (MemberArguments != null && MemberArguments.Count > 0) {
208                                         var args = MemberArguments.Select (a => FormatNamespace (a) + a.ToCompleteTypeName ('+') + ModToString (a));
209                                         result += string.Join (",", args);
210                                 }
211                                 result += ')';
212                         }
213
214                         return result;
215                 }
216
217                 public string ToEcmaCref ()
218                 {
219                         var sb = new StringBuilder ();
220                         // Cref type
221                         sb.Append (DescKind.ToString ()[0]);
222                         sb.Append (":");
223                         // Create the rest
224                         ConstructCRef (sb);
225
226                         return sb.ToString ();
227                 }
228
229                 void ConstructCRef (StringBuilder sb)
230                 {
231                         sb.Append (Namespace);
232                         if (DescKind == Kind.Namespace)
233                                 return;
234
235                         sb.Append ('.');
236                         sb.Append (TypeName);
237                         if (GenericTypeArguments != null) {
238                                 sb.Append ('<');
239                                 int i=0;
240                                 foreach (var t in GenericTypeArguments) {
241                                         if (i > 0) {
242                                                 sb.Append (",");
243                                         }
244                                         t.ConstructCRef (sb);
245
246                                         i++;
247                                 }
248                                 sb.Append ('>');
249                         }
250                         if (NestedType != null) {
251                                 sb.Append ('+');
252                                 NestedType.ConstructCRef (sb);
253                         }
254                         if (ArrayDimensions != null && ArrayDimensions.Count > 0) {
255                                 for (int i = 0; i < ArrayDimensions.Count; i++) {
256                                         sb.Append ('[');
257                                         sb.Append (new string (',', ArrayDimensions[i] - 1));
258                                         sb.Append (']');
259                                 }
260                         }
261                         if (DescKind == Kind.Type)
262                                 return;
263
264                         sb.Append (".");
265                         sb.Append (MemberName);
266
267                         if (MemberArguments != null && MemberArgumentsCount > 0) {
268                                 sb.Append ("(");
269                                 int i=0;
270                                 foreach (var a in MemberArguments) {
271                                         if (i > 0) {
272                                                 sb.Append(",");
273                                         }
274                                         a.ConstructCRef (sb);
275                                         i++;
276                                 }
277                                 sb.Append (")");
278                         }
279                 }
280
281                 public override string ToString ()
282                 {
283                         return string.Format ("({8}) {0}::{1}{2}{3}{7} {4}{5}{6} {9} {10}",
284                                               Namespace,
285                                               TypeName,
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);
295                                               
296                 }
297
298                 public override bool Equals (object other)
299                 {
300                         var otherDesc = other as EcmaDesc;
301                         return otherDesc != null && Equals (otherDesc);
302                 }
303
304                 public bool Equals (EcmaDesc other)
305                 {
306                         if (other == null)
307                                 return false;
308
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)
315                                 return false;
316
317                         return other != 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))
327                                 && Etc == other.Etc
328                                 && EtcFilter == other.EtcFilter
329                                 && (ExplicitImplMember == null || ExplicitImplMember.Equals (other.ExplicitImplMember));
330                 }
331
332                 public override int GetHashCode ()
333                 {
334                         return DescKind.GetHashCode ()
335                                 ^ TypeName.GetHashCode ()
336                                 ^ Namespace.GetHashCode ()
337                                 ^ MemberName.GetHashCode ();
338                 }
339
340                 bool What (bool input)
341                 {
342                         if (!input)
343                                 throw new Exception ("Not equal");
344                         return input;
345                 }
346
347                 bool WhatT (bool input)
348                 {
349                         if (input)
350                                 throw new Exception ("Not equal");
351                         return input;
352                 }
353
354                 string FormatNamespace (EcmaDesc desc)
355                 {
356                         return string.IsNullOrEmpty (desc.Namespace) ? string.Empty : desc.Namespace + ".";
357                 }
358
359                 string FormatGenericArgs (IEnumerable<EcmaDesc> args)
360                 {
361                         if (args == null || !args.Any ())
362                                 return string.Empty;
363                         // If we only have the number of generic arguments, use ` notation
364                         if (args.First () == null)
365                                 return "`" + args.Count ();
366
367                         IEnumerable<string> argsList = args.Select (t => FormatNamespace (t) + t.ToCompleteTypeName ());
368
369                         return "<" + string.Join (",", argsList) + ">";
370                 }
371
372                 string FormatGenericArgsFull (IEnumerable<EcmaDesc> genericArgs)
373                 {
374                         return genericArgs != null ? "<" + string.Join (",", genericArgs.Select (t => t.ToString ())) + ">" : string.Empty;
375                 }
376
377                 string ModToString (EcmaDesc desc)
378                 {
379                         switch (desc.DescModifier) {
380                         case Mod.Pointer:
381                                 return "*";
382                         case Mod.Ref:
383                                 return "&";
384                         case Mod.Out:
385                                 return "@";
386                         default:
387                                 return string.Empty;
388                         }
389                 }
390
391                 string FormattedNamespace {
392                         get {
393                                 return !string.IsNullOrEmpty (Namespace) ? Namespace + "." : string.Empty;
394                         }
395                 }
396         }
397 }