c9f8da26fc666eda0eb9ea3f7c30e5c347d72c45
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / Signature.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.core;
12
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14
15 /**
16  * Provides methods for encoding and decoding type and method signature strings.
17  * <p>
18  * The syntax for a type signature is:
19  * 
20  * <pre>
21  *  typeSignature ::=
22  *      &quot;B&quot;  // byte
23  *    | &quot;C&quot;  // char
24  *    | &quot;D&quot;  // double
25  *    | &quot;F&quot;  // float
26  *    | &quot;I&quot;  // int
27  *    | &quot;J&quot;  // long
28  *    | &quot;S&quot;  // short
29  *    | &quot;V&quot;  // void
30  *    | &quot;Z&quot;  // boolean
31  *    | &quot;L&quot; + binaryTypeName + &quot;;&quot;  // resolved named type (in compiled code)
32  *    | &quot;Q&quot; + sourceTypeName + &quot;;&quot;  // unresolved named type (in source code)
33  *    | &quot;[&quot; + typeSignature  // array of type denoted by typeSignature
34  * </pre>
35  * 
36  * </p>
37  * <p>
38  * Examples:
39  * <ul>
40  * <li><code>"[[I"</code> denotes <code>int[][]</code></li>
41  * <li><code>"Ljava.lang.String;"</code> denotes
42  * <code>java.lang.String</code> in compiled code</li>
43  * <li><code>"QString"</code> denotes <code>String</code> in source code</li>
44  * <li><code>"Qjava.lang.String"</code> denotes <code>java.lang.String</code>
45  * in source code</li>
46  * <li><code>"[QString"</code> denotes <code>String[]</code> in source code</li>
47  * </ul>
48  * </p>
49  * <p>
50  * The syntax for a method signature is:
51  * 
52  * <pre>
53  *  methodSignature ::= &quot;(&quot; + paramTypeSignature* + &quot;)&quot; + returnTypeSignature
54  *  paramTypeSignature ::= typeSignature
55  *  returnTypeSignature ::= typeSignature
56  * </pre>
57  * 
58  * <p>
59  * Examples:
60  * <ul>
61  * <li><code>"()I"</code> denotes <code>int foo()</code></li>
62  * <li><code>"([Ljava.lang.String;)V"</code> denotes
63  * <code>void foo(java.lang.String[])</code> in compiled code</li>
64  * <li><code>"(QString;)QObject;"</code> denotes
65  * <code>Object foo(String)</code> in source code</li>
66  * </ul>
67  * </p>
68  * <p>
69  * This class provides static methods and constants only; it is not intended to
70  * be instantiated or subclassed by clients.
71  * </p>
72  */
73 public final class Signature {
74
75         /**
76          * Character constant indicating the primitive type boolean in a signature.
77          * Value is <code>'Z'</code>.
78          */
79         public static final char C_BOOLEAN = 'Z';
80
81         /**
82          * Character constant indicating the primitive type byte in a signature.
83          * Value is <code>'B'</code>.
84          */
85         public static final char C_BYTE = 'B';
86
87         /**
88          * Character constant indicating the primitive type char in a signature.
89          * Value is <code>'C'</code>.
90          */
91         public static final char C_CHAR = 'C';
92
93         /**
94          * Character constant indicating the primitive type double in a signature.
95          * Value is <code>'D'</code>.
96          */
97         public static final char C_DOUBLE = 'D';
98
99         /**
100          * Character constant indicating the primitive type float in a signature.
101          * Value is <code>'F'</code>.
102          */
103         public static final char C_FLOAT = 'F';
104
105         /**
106          * Character constant indicating the primitive type int in a signature.
107          * Value is <code>'I'</code>.
108          */
109         public static final char C_INT = 'I';
110
111         /**
112          * Character constant indicating the semicolon in a signature. Value is
113          * <code>';'</code>.
114          */
115         public static final char C_SEMICOLON = ';';
116
117         /**
118          * Character constant indicating the primitive type long in a signature.
119          * Value is <code>'J'</code>.
120          */
121         public static final char C_LONG = 'J';
122
123         /**
124          * Character constant indicating the primitive type short in a signature.
125          * Value is <code>'S'</code>.
126          */
127         public static final char C_SHORT = 'S';
128
129         /**
130          * Character constant indicating result type void in a signature. Value is
131          * <code>'V'</code>.
132          */
133         public static final char C_VOID = 'V';
134
135         /**
136          * Character constant indicating the dot in a signature. Value is
137          * <code>'.'</code>.
138          */
139         public static final char C_DOT = '.';
140
141         /**
142          * Character constant indicating the dollar in a signature. Value is
143          * <code>'$'</code>.
144          */
145         public static final char C_DOLLAR = '$';
146
147         /**
148          * Character constant indicating an array type in a signature. Value is
149          * <code>'['</code>.
150          */
151         public static final char C_ARRAY = '[';
152
153         /**
154          * Character constant indicating the start of a resolved, named type in a
155          * signature. Value is <code>'L'</code>.
156          */
157         public static final char C_RESOLVED = 'L';
158
159         /**
160          * Character constant indicating the start of an unresolved, named type in a
161          * signature. Value is <code>'Q'</code>.
162          */
163         public static final char C_UNRESOLVED = 'Q';
164
165         /**
166          * Character constant indicating the end of a named type in a signature.
167          * Value is <code>';'</code>.
168          */
169         public static final char C_NAME_END = ';';
170
171         /**
172          * Character constant indicating the start of a parameter type list in a
173          * signature. Value is <code>'('</code>.
174          */
175         public static final char C_PARAM_START = '(';
176
177         /**
178          * Character constant indicating the end of a parameter type list in a
179          * signature. Value is <code>')'</code>.
180          */
181         public static final char C_PARAM_END = ')';
182
183         /**
184          * String constant for the signature of the primitive type boolean. Value is
185          * <code>"Z"</code>.
186          */
187         public static final String SIG_BOOLEAN = "Z"; //$NON-NLS-1$
188
189         /**
190          * String constant for the signature of the primitive type byte. Value is
191          * <code>"B"</code>.
192          */
193         public static final String SIG_BYTE = "B"; //$NON-NLS-1$
194
195         /**
196          * String constant for the signature of the primitive type char. Value is
197          * <code>"C"</code>.
198          */
199         public static final String SIG_CHAR = "C"; //$NON-NLS-1$
200
201         /**
202          * String constant for the signature of the primitive type double. Value is
203          * <code>"D"</code>.
204          */
205         public static final String SIG_DOUBLE = "D"; //$NON-NLS-1$
206
207         /**
208          * String constant for the signature of the primitive type float. Value is
209          * <code>"F"</code>.
210          */
211         public static final String SIG_FLOAT = "F"; //$NON-NLS-1$
212
213         /**
214          * String constant for the signature of the primitive type int. Value is
215          * <code>"I"</code>.
216          */
217         public static final String SIG_INT = "I"; //$NON-NLS-1$
218
219         /**
220          * String constant for the signature of the primitive type long. Value is
221          * <code>"J"</code>.
222          */
223         public static final String SIG_LONG = "J"; //$NON-NLS-1$
224
225         /**
226          * String constant for the signature of the primitive type short. Value is
227          * <code>"S"</code>.
228          */
229         public static final String SIG_SHORT = "S"; //$NON-NLS-1$
230
231         /**
232          * String constant for the signature of result type void. Value is
233          * <code>"V"</code>.
234          */
235         public static final String SIG_VOID = "V"; //$NON-NLS-1$
236
237         private static final char[] BOOLEAN = { 'b', 'o', 'o', 'l', 'e', 'a', 'n' };
238
239         private static final char[] BYTE = { 'b', 'y', 't', 'e' };
240
241         private static final char[] CHAR = { 'c', 'h', 'a', 'r' };
242
243         private static final char[] DOUBLE = { 'd', 'o', 'u', 'b', 'l', 'e' };
244
245         private static final char[] FLOAT = { 'f', 'l', 'o', 'a', 't' };
246
247         private static final char[] INT = { 'i', 'n', 't' };
248
249         private static final char[] LONG = { 'l', 'o', 'n', 'g' };
250
251         private static final char[] SHORT = { 's', 'h', 'o', 'r', 't' };
252
253         private static final char[] VOID = { 'v', 'o', 'i', 'd' };
254
255         private static final String EMPTY = new String(CharOperation.NO_CHAR);
256
257         /**
258          * Not instantiable.
259          */
260         private Signature() {
261         }
262
263         private static long copyType(char[] signature, int sigPos, char[] dest,
264                         int index, boolean fullyQualifyTypeNames) {
265                 int arrayCount = 0;
266                 loop: while (true) {
267                         switch (signature[sigPos++]) {
268                         case C_ARRAY:
269                                 arrayCount++;
270                                 break;
271                         case C_BOOLEAN:
272                                 int length = BOOLEAN.length;
273                                 System.arraycopy(BOOLEAN, 0, dest, index, length);
274                                 index += length;
275                                 break loop;
276                         case C_BYTE:
277                                 length = BYTE.length;
278                                 System.arraycopy(BYTE, 0, dest, index, length);
279                                 index += length;
280                                 break loop;
281                         case C_CHAR:
282                                 length = CHAR.length;
283                                 System.arraycopy(CHAR, 0, dest, index, length);
284                                 index += length;
285                                 break loop;
286                         case C_DOUBLE:
287                                 length = DOUBLE.length;
288                                 System.arraycopy(DOUBLE, 0, dest, index, length);
289                                 index += length;
290                                 break loop;
291                         case C_FLOAT:
292                                 length = FLOAT.length;
293                                 System.arraycopy(FLOAT, 0, dest, index, length);
294                                 index += length;
295                                 break loop;
296                         case C_INT:
297                                 length = INT.length;
298                                 System.arraycopy(INT, 0, dest, index, length);
299                                 index += length;
300                                 break loop;
301                         case C_LONG:
302                                 length = LONG.length;
303                                 System.arraycopy(LONG, 0, dest, index, length);
304                                 index += length;
305                                 break loop;
306                         case C_SHORT:
307                                 length = SHORT.length;
308                                 System.arraycopy(SHORT, 0, dest, index, length);
309                                 index += length;
310                                 break loop;
311                         case C_VOID:
312                                 length = VOID.length;
313                                 System.arraycopy(VOID, 0, dest, index, length);
314                                 index += length;
315                                 break loop;
316                         case C_RESOLVED:
317                         case C_UNRESOLVED:
318                                 int end = CharOperation.indexOf(C_SEMICOLON, signature, sigPos);
319                                 if (end == -1)
320                                         throw new IllegalArgumentException();
321                                 int start;
322                                 if (fullyQualifyTypeNames) {
323                                         start = sigPos;
324                                 } else {
325                                         start = CharOperation.lastIndexOf(C_DOT, signature, sigPos,
326                                                         end) + 1;
327                                         if (start == 0)
328                                                 start = sigPos;
329                                 }
330                                 length = end - start;
331                                 System.arraycopy(signature, start, dest, index, length);
332                                 sigPos = end + 1;
333                                 index += length;
334                                 break loop;
335                         }
336                 }
337                 while (arrayCount-- > 0) {
338                         dest[index++] = '[';
339                         dest[index++] = ']';
340                 }
341                 return (((long) index) << 32) + sigPos;
342         }
343
344         /**
345          * Creates a new type signature with the given amount of array nesting added
346          * to the given type signature.
347          * 
348          * @param typeSignature
349          *            the type signature
350          * @param arrayCount
351          *            the desired number of levels of array nesting
352          * @return the encoded array type signature
353          * 
354          * @since 2.0
355          */
356         public static char[] createArraySignature(char[] typeSignature,
357                         int arrayCount) {
358                 if (arrayCount == 0)
359                         return typeSignature;
360                 int sigLength = typeSignature.length;
361                 char[] result = new char[arrayCount + sigLength];
362                 for (int i = 0; i < arrayCount; i++) {
363                         result[i] = C_ARRAY;
364                 }
365                 System.arraycopy(typeSignature, 0, result, arrayCount, sigLength);
366                 return result;
367         }
368
369         /**
370          * Creates a new type signature with the given amount of array nesting added
371          * to the given type signature.
372          * 
373          * @param typeSignature
374          *            the type signature
375          * @param arrayCount
376          *            the desired number of levels of array nesting
377          * @return the encoded array type signature
378          */
379         public static String createArraySignature(String typeSignature,
380                         int arrayCount) {
381                 return new String(createArraySignature(typeSignature.toCharArray(),
382                                 arrayCount));
383         }
384
385         /**
386          * Creates a method signature from the given parameter and return type
387          * signatures. The encoded method signature is dot-based.
388          * 
389          * @param parameterTypes
390          *            the list of parameter type signatures
391          * @param returnType
392          *            the return type signature
393          * @return the encoded method signature
394          * 
395          * @since 2.0
396          */
397         public static char[] createMethodSignature(char[][] parameterTypes,
398                         char[] returnType) {
399                 int parameterTypesLength = parameterTypes.length;
400                 int parameterLength = 0;
401                 for (int i = 0; i < parameterTypesLength; i++) {
402                         parameterLength += parameterTypes[i].length;
403
404                 }
405                 int returnTypeLength = returnType.length;
406                 char[] result = new char[1 + parameterLength + 1 + returnTypeLength];
407                 result[0] = C_PARAM_START;
408                 int index = 1;
409                 for (int i = 0; i < parameterTypesLength; i++) {
410                         char[] parameterType = parameterTypes[i];
411                         int length = parameterType.length;
412                         System.arraycopy(parameterType, 0, result, index, length);
413                         index += length;
414                 }
415                 result[index] = C_PARAM_END;
416                 System.arraycopy(returnType, 0, result, index + 1, returnTypeLength);
417                 return result;
418         }
419
420         /**
421          * Creates a method signature from the given parameter and return type
422          * signatures. The encoded method signature is dot-based.
423          * 
424          * @param parameterTypes
425          *            the list of parameter type signatures
426          * @param returnType
427          *            the return type signature
428          * @return the encoded method signature
429          */
430         public static String createMethodSignature(String[] parameterTypes,
431                         String returnType) {
432                 int parameterTypesLenth = parameterTypes.length;
433                 char[][] parameters = new char[parameterTypesLenth][];
434                 for (int i = 0; i < parameterTypesLenth; i++) {
435                         parameters[i] = parameterTypes[i].toCharArray();
436                 }
437                 return new String(createMethodSignature(parameters, returnType
438                                 .toCharArray()));
439         }
440
441         /**
442          * Creates a new type signature from the given type name encoded as a
443          * character array. This method is equivalent to
444          * <code>createTypeSignature(new String(typeName),isResolved)</code>,
445          * although more efficient for callers with character arrays rather than
446          * strings. If the type name is qualified, then it is expected to be
447          * dot-based.
448          * 
449          * @param typeName
450          *            the possibly qualified type name
451          * @param isResolved
452          *            <code>true</code> if the type name is to be considered
453          *            resolved (for example, a type name from a binary class file),
454          *            and <code>false</code> if the type name is to be considered
455          *            unresolved (for example, a type name found in source code)
456          * @return the encoded type signature
457          * @see #createTypeSignature(java.lang.String,boolean)
458          */
459         public static String createTypeSignature(char[] typeName, boolean isResolved) {
460                 return new String(createCharArrayTypeSignature(typeName, isResolved));
461         }
462
463         /**
464          * Creates a new type signature from the given type name encoded as a
465          * character array. This method is equivalent to
466          * <code>createTypeSignature(new String(typeName),isResolved).toCharArray()</code>,
467          * although more efficient for callers with character arrays rather than
468          * strings. If the type name is qualified, then it is expected to be
469          * dot-based.
470          * 
471          * @param typeName
472          *            the possibly qualified type name
473          * @param isResolved
474          *            <code>true</code> if the type name is to be considered
475          *            resolved (for example, a type name from a binary class file),
476          *            and <code>false</code> if the type name is to be considered
477          *            unresolved (for example, a type name found in source code)
478          * @return the encoded type signature
479          * @see #createTypeSignature(java.lang.String,boolean)
480          * 
481          * @since 2.0
482          */
483         public static char[] createCharArrayTypeSignature(char[] typeName,
484                         boolean isResolved) {
485
486                 if (typeName == null)
487                         throw new IllegalArgumentException("null"); //$NON-NLS-1$
488                 int length = typeName.length;
489                 if (length == 0)
490                         throw new IllegalArgumentException(new String(typeName));
491
492                 int arrayCount = CharOperation.occurencesOf('[', typeName);
493                 char[] sig;
494
495                 switch (typeName[0]) {
496                 // primitive type?
497                 case 'b':
498                         if (CharOperation.fragmentEquals(BOOLEAN, typeName, 0, true)) {
499                                 sig = new char[arrayCount + 1];
500                                 sig[arrayCount] = C_BOOLEAN;
501                                 break;
502                         } else if (CharOperation.fragmentEquals(BYTE, typeName, 0, true)) {
503                                 sig = new char[arrayCount + 1];
504                                 sig[arrayCount] = C_BYTE;
505                                 break;
506                         }
507                 case 'c':
508                         if (CharOperation.fragmentEquals(CHAR, typeName, 0, true)) {
509                                 sig = new char[arrayCount + 1];
510                                 sig[arrayCount] = C_CHAR;
511                                 break;
512                         }
513                 case 'd':
514                         if (CharOperation.fragmentEquals(DOUBLE, typeName, 0, true)) {
515                                 sig = new char[arrayCount + 1];
516                                 sig[arrayCount] = C_DOUBLE;
517                                 break;
518                         }
519                 case 'f':
520                         if (CharOperation.fragmentEquals(FLOAT, typeName, 0, true)) {
521                                 sig = new char[arrayCount + 1];
522                                 sig[arrayCount] = C_FLOAT;
523                                 break;
524                         }
525                 case 'i':
526                         if (CharOperation.fragmentEquals(INT, typeName, 0, true)) {
527                                 sig = new char[arrayCount + 1];
528                                 sig[arrayCount] = C_INT;
529                                 break;
530                         }
531                 case 'l':
532                         if (CharOperation.fragmentEquals(LONG, typeName, 0, true)) {
533                                 sig = new char[arrayCount + 1];
534                                 sig[arrayCount] = C_LONG;
535                                 break;
536                         }
537                 case 's':
538                         if (CharOperation.fragmentEquals(SHORT, typeName, 0, true)) {
539                                 sig = new char[arrayCount + 1];
540                                 sig[arrayCount] = C_SHORT;
541                                 break;
542                         }
543                 case 'v':
544                         if (CharOperation.fragmentEquals(VOID, typeName, 0, true)) {
545                                 sig = new char[arrayCount + 1];
546                                 sig[arrayCount] = C_VOID;
547                                 break;
548                         }
549                 default:
550                         // non primitive type
551                         int sigLength = arrayCount + 1 + length + 1; // for example
552                                                                                                                         // '[[[Ljava.lang.String;'
553                         sig = new char[sigLength];
554                         int sigIndex = arrayCount + 1; // index in sig
555                         int startID = 0; // start of current ID in typeName
556                         int index = 0; // index in typeName
557                         while (index < length) {
558                                 char currentChar = typeName[index];
559                                 switch (currentChar) {
560                                 case '.':
561                                         if (startID == -1)
562                                                 throw new IllegalArgumentException(new String(typeName));
563                                         if (startID < index) {
564                                                 sig = CharOperation.append(sig, sigIndex, typeName,
565                                                                 startID, index);
566                                                 sigIndex += index - startID;
567                                         }
568                                         sig[sigIndex++] = C_DOT;
569                                         index++;
570                                         startID = index;
571                                         break;
572                                 case '[':
573                                         if (startID != -1) {
574                                                 if (startID < index) {
575                                                         sig = CharOperation.append(sig, sigIndex, typeName,
576                                                                         startID, index);
577                                                         sigIndex += index - startID;
578                                                 }
579                                                 startID = -1; // no more id after []
580                                         }
581                                         index++;
582                                         break;
583                                 default:
584                                         if (startID != -1
585                                                         && CharOperation.isWhitespace(currentChar)) {
586                                                 if (startID < index) {
587                                                         sig = CharOperation.append(sig, sigIndex, typeName,
588                                                                         startID, index);
589                                                         sigIndex += index - startID;
590                                                 }
591                                                 startID = index + 1;
592                                         }
593                                         index++;
594                                         break;
595                                 }
596                         }
597                         // last id
598                         if (startID != -1 && startID < index) {
599                                 sig = CharOperation.append(sig, sigIndex, typeName, startID,
600                                                 index);
601                                 sigIndex += index - startID;
602                         }
603
604                         // add L (or Q) at the beigininig and ; at the end
605                         sig[arrayCount] = isResolved ? C_RESOLVED : C_UNRESOLVED;
606                         sig[sigIndex++] = C_NAME_END;
607
608                         // resize if needed
609                         if (sigLength > sigIndex) {
610                                 System.arraycopy(sig, 0, sig = new char[sigIndex], 0, sigIndex);
611                         }
612                 }
613
614                 // add array info
615                 for (int i = 0; i < arrayCount; i++) {
616                         sig[i] = C_ARRAY;
617                 }
618
619                 return sig;
620         }
621
622         /**
623          * Creates a new type signature from the given type name. If the type name
624          * is qualified, then it is expected to be dot-based.
625          * <p>
626          * For example:
627          * 
628          * <pre>
629          * <code>
630          *  createTypeSignature(&quot;int&quot;, hucairz) -&gt; &quot;I&quot;
631          *  createTypeSignature(&quot;java.lang.String&quot;, true) -&gt; &quot;Ljava.lang.String;&quot;
632          *  createTypeSignature(&quot;String&quot;, false) -&gt; &quot;QString;&quot;
633          *  createTypeSignature(&quot;java.lang.String&quot;, false) -&gt; &quot;Qjava.lang.String;&quot;
634          *  createTypeSignature(&quot;int []&quot;, false) -&gt; &quot;[I&quot;
635          * </code>
636          * </pre>
637          * 
638          * </p>
639          * 
640          * @param typeName
641          *            the possibly qualified type name
642          * @param isResolved
643          *            <code>true</code> if the type name is to be considered
644          *            resolved (for example, a type name from a binary class file),
645          *            and <code>false</code> if the type name is to be considered
646          *            unresolved (for example, a type name found in source code)
647          * @return the encoded type signature
648          */
649         public static String createTypeSignature(String typeName, boolean isResolved) {
650                 return createTypeSignature(typeName == null ? null : typeName
651                                 .toCharArray(), isResolved);
652         }
653
654         /**
655          * Returns the array count (array nesting depth) of the given type
656          * signature.
657          * 
658          * @param typeSignature
659          *            the type signature
660          * @return the array nesting depth, or 0 if not an array
661          * @exception IllegalArgumentException
662          *                if the signature is not syntactically correct
663          * 
664          * @since 2.0
665          */
666         public static int getArrayCount(char[] typeSignature)
667                         throws IllegalArgumentException {
668                 try {
669                         int count = 0;
670                         while (typeSignature[count] == C_ARRAY) {
671                                 ++count;
672                         }
673                         return count;
674                 } catch (ArrayIndexOutOfBoundsException e) { // signature is
675                                                                                                                 // syntactically
676                                                                                                                 // incorrect if last
677                                                                                                                 // character is C_ARRAY
678                         throw new IllegalArgumentException();
679                 }
680         }
681
682         /**
683          * Returns the array count (array nesting depth) of the given type
684          * signature.
685          * 
686          * @param typeSignature
687          *            the type signature
688          * @return the array nesting depth, or 0 if not an array
689          * @exception IllegalArgumentException
690          *                if the signature is not syntactically correct
691          */
692         public static int getArrayCount(String typeSignature)
693                         throws IllegalArgumentException {
694                 return getArrayCount(typeSignature.toCharArray());
695         }
696
697         /**
698          * Returns the type signature without any array nesting.
699          * <p>
700          * For example:
701          * 
702          * <pre>
703          * <code>
704          *  getElementType({'[', '[', 'I'}) --&gt; {'I'}.
705          * </code>
706          * </pre>
707          * 
708          * </p>
709          * 
710          * @param typeSignature
711          *            the type signature
712          * @return the type signature without arrays
713          * @exception IllegalArgumentException
714          *                if the signature is not syntactically correct
715          * 
716          * @since 2.0
717          */
718         public static char[] getElementType(char[] typeSignature)
719                         throws IllegalArgumentException {
720                 int count = getArrayCount(typeSignature);
721                 if (count == 0)
722                         return typeSignature;
723                 int length = typeSignature.length;
724                 char[] result = new char[length - count];
725                 System.arraycopy(typeSignature, count, result, 0, length - count);
726                 return result;
727         }
728
729         /**
730          * Returns the type signature without any array nesting.
731          * <p>
732          * For example:
733          * 
734          * <pre>
735          * <code>
736          *  getElementType(&quot;[[I&quot;) --&gt; &quot;I&quot;.
737          * </code>
738          * </pre>
739          * 
740          * </p>
741          * 
742          * @param typeSignature
743          *            the type signature
744          * @return the type signature without arrays
745          * @exception IllegalArgumentException
746          *                if the signature is not syntactically correct
747          */
748         public static String getElementType(String typeSignature)
749                         throws IllegalArgumentException {
750                 return new String(getElementType(typeSignature.toCharArray()));
751         }
752
753         /**
754          * Returns the number of parameter types in the given method signature.
755          * 
756          * @param methodSignature
757          *            the method signature
758          * @return the number of parameters
759          * @exception IllegalArgumentException
760          *                if the signature is not syntactically correct
761          * @since 2.0
762          */
763         public static int getParameterCount(char[] methodSignature)
764                         throws IllegalArgumentException {
765                 try {
766                         int count = 0;
767                         int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1;
768                         if (i == 0)
769                                 throw new IllegalArgumentException();
770                         for (;;) {
771                                 char c = methodSignature[i++];
772                                 switch (c) {
773                                 case C_ARRAY:
774                                         break;
775                                 case C_BOOLEAN:
776                                 case C_BYTE:
777                                 case C_CHAR:
778                                 case C_DOUBLE:
779                                 case C_FLOAT:
780                                 case C_INT:
781                                 case C_LONG:
782                                 case C_SHORT:
783                                 case C_VOID:
784                                         ++count;
785                                         break;
786                                 case C_RESOLVED:
787                                 case C_UNRESOLVED:
788                                         i = CharOperation.indexOf(C_SEMICOLON, methodSignature, i) + 1;
789                                         if (i == 0)
790                                                 throw new IllegalArgumentException();
791                                         ++count;
792                                         break;
793                                 case C_PARAM_END:
794                                         return count;
795                                 default:
796                                         throw new IllegalArgumentException();
797                                 }
798                         }
799                 } catch (ArrayIndexOutOfBoundsException e) {
800                         throw new IllegalArgumentException();
801                 }
802         }
803
804         /**
805          * Returns the number of parameter types in the given method signature.
806          * 
807          * @param methodSignature
808          *            the method signature
809          * @return the number of parameters
810          * @exception IllegalArgumentException
811          *                if the signature is not syntactically correct
812          */
813         public static int getParameterCount(String methodSignature)
814                         throws IllegalArgumentException {
815                 return getParameterCount(methodSignature.toCharArray());
816         }
817
818         /**
819          * Extracts the parameter type signatures from the given method signature.
820          * The method signature is expected to be dot-based.
821          * 
822          * @param methodSignature
823          *            the method signature
824          * @return the list of parameter type signatures
825          * @exception IllegalArgumentException
826          *                if the signature is syntactically incorrect
827          * 
828          * @since 2.0
829          */
830         public static char[][] getParameterTypes(char[] methodSignature)
831                         throws IllegalArgumentException {
832                 try {
833                         int count = getParameterCount(methodSignature);
834                         char[][] result = new char[count][];
835                         if (count == 0)
836                                 return result;
837                         int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1;
838                         count = 0;
839                         int start = i;
840                         for (;;) {
841                                 char c = methodSignature[i++];
842                                 switch (c) {
843                                 case C_ARRAY:
844                                         // array depth is i - start;
845                                         break;
846                                 case C_BOOLEAN:
847                                 case C_BYTE:
848                                 case C_CHAR:
849                                 case C_DOUBLE:
850                                 case C_FLOAT:
851                                 case C_INT:
852                                 case C_LONG:
853                                 case C_SHORT:
854                                 case C_VOID:
855                                         // common case of base types
856                                         if (i - start == 1) {
857                                                 switch (c) {
858                                                 case C_BOOLEAN:
859                                                         result[count++] = new char[] { C_BOOLEAN };
860                                                         break;
861                                                 case C_BYTE:
862                                                         result[count++] = new char[] { C_BYTE };
863                                                         break;
864                                                 case C_CHAR:
865                                                         result[count++] = new char[] { C_CHAR };
866                                                         break;
867                                                 case C_DOUBLE:
868                                                         result[count++] = new char[] { C_DOUBLE };
869                                                         break;
870                                                 case C_FLOAT:
871                                                         result[count++] = new char[] { C_FLOAT };
872                                                         break;
873                                                 case C_INT:
874                                                         result[count++] = new char[] { C_INT };
875                                                         break;
876                                                 case C_LONG:
877                                                         result[count++] = new char[] { C_LONG };
878                                                         break;
879                                                 case C_SHORT:
880                                                         result[count++] = new char[] { C_SHORT };
881                                                         break;
882                                                 case C_VOID:
883                                                         result[count++] = new char[] { C_VOID };
884                                                         break;
885                                                 }
886                                         } else {
887                                                 result[count++] = CharOperation.subarray(
888                                                                 methodSignature, start, i);
889                                         }
890                                         start = i;
891                                         break;
892                                 case C_RESOLVED:
893                                 case C_UNRESOLVED:
894                                         i = CharOperation.indexOf(C_SEMICOLON, methodSignature, i) + 1;
895                                         if (i == 0)
896                                                 throw new IllegalArgumentException();
897                                         result[count++] = CharOperation.subarray(methodSignature,
898                                                         start, i);
899                                         start = i;
900                                         break;
901                                 case C_PARAM_END:
902                                         return result;
903                                 default:
904                                         throw new IllegalArgumentException();
905                                 }
906                         }
907                 } catch (ArrayIndexOutOfBoundsException e) {
908                         throw new IllegalArgumentException();
909                 }
910         }
911
912         /**
913          * Extracts the parameter type signatures from the given method signature.
914          * The method signature is expected to be dot-based.
915          * 
916          * @param methodSignature
917          *            the method signature
918          * @return the list of parameter type signatures
919          * @exception IllegalArgumentException
920          *                if the signature is syntactically incorrect
921          */
922         public static String[] getParameterTypes(String methodSignature)
923                         throws IllegalArgumentException {
924                 char[][] parameterTypes = getParameterTypes(methodSignature
925                                 .toCharArray());
926                 int length = parameterTypes.length;
927                 String[] result = new String[length];
928                 for (int i = 0; i < length; i++) {
929                         result[i] = new String(parameterTypes[i]);
930                 }
931                 return result;
932         }
933
934         /**
935          * Returns a char array containing all but the last segment of the given
936          * dot-separated qualified name. Returns the empty char array if it is not
937          * qualified.
938          * <p>
939          * For example:
940          * 
941          * <pre>
942          * <code>
943          *  getQualifier({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -&gt; {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g'}
944          *  getQualifier({'O', 'u', 't', 'e', 'r', '.', 'I', 'n', 'n', 'e', 'r'}) -&gt; {'O', 'u', 't', 'e', 'r'}
945          * </code>
946          * </pre>
947          * 
948          * </p>
949          * 
950          * @param name
951          *            the name
952          * @return the qualifier prefix, or the empty char array if the name
953          *         contains no dots
954          * @exception NullPointerException
955          *                if name is null
956          * @since 2.0
957          */
958         public static char[] getQualifier(char[] name) {
959                 int lastDot = CharOperation.lastIndexOf(C_DOT, name);
960                 if (lastDot == -1) {
961                         return CharOperation.NO_CHAR;
962                 }
963                 return CharOperation.subarray(name, 0, lastDot);
964         }
965
966         /**
967          * Returns a string containing all but the last segment of the given
968          * dot-separated qualified name. Returns the empty string if it is not
969          * qualified.
970          * <p>
971          * For example:
972          * 
973          * <pre>
974          * <code>
975          *  getQualifier(&quot;java.lang.Object&quot;) -&gt; &quot;java.lang&quot;
976          *  getQualifier(&quot;Outer.Inner&quot;) -&gt; &quot;Outer&quot;
977          * </code>
978          * </pre>
979          * 
980          * </p>
981          * 
982          * @param name
983          *            the name
984          * @return the qualifier prefix, or the empty string if the name contains no
985          *         dots
986          * @exception NullPointerException
987          *                if name is null
988          */
989         public static String getQualifier(String name) {
990                 int lastDot = name.lastIndexOf(C_DOT);
991                 if (lastDot == -1) {
992                         return EMPTY;
993                 }
994                 return name.substring(0, lastDot);
995         }
996
997         /**
998          * Extracts the return type from the given method signature. The method
999          * signature is expected to be dot-based.
1000          * 
1001          * @param methodSignature
1002          *            the method signature
1003          * @return the type signature of the return type
1004          * @exception IllegalArgumentException
1005          *                if the signature is syntactically incorrect
1006          * 
1007          * @since 2.0
1008          */
1009         public static char[] getReturnType(char[] methodSignature)
1010                         throws IllegalArgumentException {
1011                 int i = CharOperation.lastIndexOf(C_PARAM_END, methodSignature);
1012                 if (i == -1) {
1013                         throw new IllegalArgumentException();
1014                 }
1015                 return CharOperation.subarray(methodSignature, i + 1,
1016                                 methodSignature.length);
1017         }
1018
1019         /**
1020          * Extracts the return type from the given method signature. The method
1021          * signature is expected to be dot-based.
1022          * 
1023          * @param methodSignature
1024          *            the method signature
1025          * @return the type signature of the return type
1026          * @exception IllegalArgumentException
1027          *                if the signature is syntactically incorrect
1028          */
1029         public static String getReturnType(String methodSignature)
1030                         throws IllegalArgumentException {
1031                 return new String(getReturnType(methodSignature.toCharArray()));
1032         }
1033
1034         /**
1035          * Returns the last segment of the given dot-separated qualified name.
1036          * Returns the given name if it is not qualified.
1037          * <p>
1038          * For example:
1039          * 
1040          * <pre>
1041          * <code>
1042          *  getSimpleName({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -&gt; {'O', 'b', 'j', 'e', 'c', 't'}
1043          * </code>
1044          * </pre>
1045          * 
1046          * </p>
1047          * 
1048          * @param name
1049          *            the name
1050          * @return the last segment of the qualified name
1051          * @exception NullPointerException
1052          *                if name is null
1053          * @since 2.0
1054          */
1055         public static char[] getSimpleName(char[] name) {
1056                 int lastDot = CharOperation.lastIndexOf(C_DOT, name);
1057                 if (lastDot == -1) {
1058                         return name;
1059                 }
1060                 return CharOperation.subarray(name, lastDot + 1, name.length);
1061         }
1062
1063         /**
1064          * Returns the last segment of the given dot-separated qualified name.
1065          * Returns the given name if it is not qualified.
1066          * <p>
1067          * For example:
1068          * 
1069          * <pre>
1070          * <code>
1071          *  getSimpleName(&quot;java.lang.Object&quot;) -&gt; &quot;Object&quot;
1072          * </code>
1073          * </pre>
1074          * 
1075          * </p>
1076          * 
1077          * @param name
1078          *            the name
1079          * @return the last segment of the qualified name
1080          * @exception NullPointerException
1081          *                if name is null
1082          */
1083         public static String getSimpleName(String name) {
1084                 int lastDot = name.lastIndexOf(C_DOT);
1085                 if (lastDot == -1) {
1086                         return name;
1087                 }
1088                 return name.substring(lastDot + 1, name.length());
1089         }
1090
1091         /**
1092          * Returns all segments of the given dot-separated qualified name. Returns
1093          * an array with only the given name if it is not qualified. Returns an
1094          * empty array if the name is empty.
1095          * <p>
1096          * For example:
1097          * 
1098          * <pre>
1099          * <code>
1100          *  getSimpleNames({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -&gt; {{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}
1101          *  getSimpleNames({'O', 'b', 'j', 'e', 'c', 't'}) -&gt; {{'O', 'b', 'j', 'e', 'c', 't'}}
1102          *  getSimpleNames(&quot;&quot;) -&gt; {}
1103          * </code>
1104          * </pre>
1105          * 
1106          * @param name
1107          *            the name
1108          * @return the list of simple names, possibly empty
1109          * @exception NullPointerException
1110          *                if name is null
1111          * @since 2.0
1112          */
1113         public static char[][] getSimpleNames(char[] name) {
1114                 if (name.length == 0) {
1115                         return CharOperation.NO_CHAR_CHAR;
1116                 }
1117                 int dot = CharOperation.indexOf(C_DOT, name);
1118                 if (dot == -1) {
1119                         return new char[][] { name };
1120                 }
1121                 int n = 1;
1122                 while ((dot = CharOperation.indexOf(C_DOT, name, dot + 1)) != -1) {
1123                         ++n;
1124                 }
1125                 char[][] result = new char[n + 1][];
1126                 int segStart = 0;
1127                 for (int i = 0; i < n; ++i) {
1128                         dot = CharOperation.indexOf(C_DOT, name, segStart);
1129                         result[i] = CharOperation.subarray(name, segStart, dot);
1130                         segStart = dot + 1;
1131                 }
1132                 result[n] = CharOperation.subarray(name, segStart, name.length);
1133                 return result;
1134         }
1135
1136         /**
1137          * Returns all segments of the given dot-separated qualified name. Returns
1138          * an array with only the given name if it is not qualified. Returns an
1139          * empty array if the name is empty.
1140          * <p>
1141          * For example:
1142          * 
1143          * <pre>
1144          * <code>
1145          *  getSimpleNames(&quot;java.lang.Object&quot;) -&gt; {&quot;java&quot;, &quot;lang&quot;, &quot;Object&quot;}
1146          *  getSimpleNames(&quot;Object&quot;) -&gt; {&quot;Object&quot;}
1147          *  getSimpleNames(&quot;&quot;) -&gt; {}
1148          * </code>
1149          * </pre>
1150          * 
1151          * @param name
1152          *            the name
1153          * @return the list of simple names, possibly empty
1154          * @exception NullPointerException
1155          *                if name is null
1156          */
1157         public static String[] getSimpleNames(String name) {
1158                 char[][] simpleNames = getSimpleNames(name.toCharArray());
1159                 int length = simpleNames.length;
1160                 String[] result = new String[length];
1161                 for (int i = 0; i < length; i++) {
1162                         result[i] = new String(simpleNames[i]);
1163                 }
1164                 return result;
1165         }
1166
1167         /**
1168          * Converts the given method signature to a readable form. The method
1169          * signature is expected to be dot-based.
1170          * <p>
1171          * For example:
1172          * 
1173          * <pre>
1174          * <code>
1175          *  toString(&quot;([Ljava.lang.String;)V&quot;, &quot;main&quot;, new String[] {&quot;args&quot;}, false, true) -&gt; &quot;void main(String[] args)&quot;
1176          * </code>
1177          * </pre>
1178          * 
1179          * </p>
1180          * 
1181          * @param methodSignature
1182          *            the method signature to convert
1183          * @param methodName
1184          *            the name of the method to insert in the result, or
1185          *            <code>null</code> if no method name is to be included
1186          * @param parameterNames
1187          *            the parameter names to insert in the result, or
1188          *            <code>null</code> if no parameter names are to be included;
1189          *            if supplied, the number of parameter names must match that of
1190          *            the method signature
1191          * @param fullyQualifyTypeNames
1192          *            <code>true</code> if type names should be fully qualified,
1193          *            and <code>false</code> to use only simple names
1194          * @param includeReturnType
1195          *            <code>true</code> if the return type is to be included
1196          * @return the char array representation of the method signature
1197          * 
1198          * @since 2.0
1199          */
1200         public static char[] toCharArray(char[] methodSignature, char[] methodName,
1201                         char[][] parameterNames, boolean fullyQualifyTypeNames,
1202                         boolean includeReturnType) {
1203                 try {
1204                         int firstParen = CharOperation.indexOf(C_PARAM_START,
1205                                         methodSignature);
1206                         if (firstParen == -1)
1207                                 throw new IllegalArgumentException();
1208
1209                         int sigLength = methodSignature.length;
1210
1211                         // compute result length
1212
1213                         // method signature
1214                         int paramCount = 0;
1215                         int lastParen = -1;
1216                         int resultLength = 0;
1217                         signature: for (int i = firstParen; i < sigLength; i++) {
1218                                 switch (methodSignature[i]) {
1219                                 case C_ARRAY:
1220                                         resultLength += 2; // []
1221                                         continue signature;
1222                                 case C_BOOLEAN:
1223                                         resultLength += BOOLEAN.length;
1224                                         break;
1225                                 case C_BYTE:
1226                                         resultLength += BYTE.length;
1227                                         break;
1228                                 case C_CHAR:
1229                                         resultLength += CHAR.length;
1230                                         break;
1231                                 case C_DOUBLE:
1232                                         resultLength += DOUBLE.length;
1233                                         break;
1234                                 case C_FLOAT:
1235                                         resultLength += FLOAT.length;
1236                                         break;
1237                                 case C_INT:
1238                                         resultLength += INT.length;
1239                                         break;
1240                                 case C_LONG:
1241                                         resultLength += LONG.length;
1242                                         break;
1243                                 case C_SHORT:
1244                                         resultLength += SHORT.length;
1245                                         break;
1246                                 case C_VOID:
1247                                         resultLength += VOID.length;
1248                                         break;
1249                                 case C_RESOLVED:
1250                                 case C_UNRESOLVED:
1251                                         int end = CharOperation.indexOf(C_SEMICOLON,
1252                                                         methodSignature, i);
1253                                         if (end == -1)
1254                                                 throw new IllegalArgumentException();
1255                                         int start;
1256                                         if (fullyQualifyTypeNames) {
1257                                                 start = i + 1;
1258                                         } else {
1259                                                 start = CharOperation.lastIndexOf(C_DOT,
1260                                                                 methodSignature, i, end) + 1;
1261                                                 if (start == 0)
1262                                                         start = i + 1;
1263                                         }
1264                                         resultLength += end - start;
1265                                         i = end;
1266                                         break;
1267                                 case C_PARAM_START:
1268                                         // add space for "("
1269                                         resultLength++;
1270                                         continue signature;
1271                                 case C_PARAM_END:
1272                                         lastParen = i;
1273                                         if (includeReturnType) {
1274                                                 if (paramCount > 0) {
1275                                                         // remove space for ", " that was added with last
1276                                                         // parameter and remove space that is going to be
1277                                                         // added for ", " after return type
1278                                                         // and add space for ") "
1279                                                         resultLength -= 2;
1280                                                 } // else
1281                                                 // remove space that is going to be added for ", " after
1282                                                 // return type
1283                                                 // and add space for ") "
1284                                                 // -> noop
1285
1286                                                 // decrement param count because it is going to be added
1287                                                 // for return type
1288                                                 paramCount--;
1289                                                 continue signature;
1290                                         } else {
1291                                                 if (paramCount > 0) {
1292                                                         // remove space for ", " that was added with last
1293                                                         // parameter and add space for ")"
1294                                                         resultLength--;
1295                                                 } else {
1296                                                         // add space for ")"
1297                                                         resultLength++;
1298                                                 }
1299                                                 break signature;
1300                                         }
1301                                 default:
1302                                         throw new IllegalArgumentException();
1303                                 }
1304                                 resultLength += 2; // add space for ", "
1305                                 paramCount++;
1306                         }
1307
1308                         // parameter names
1309                         int parameterNamesLength = parameterNames == null ? 0
1310                                         : parameterNames.length;
1311                         for (int i = 0; i < parameterNamesLength; i++) {
1312                                 resultLength += parameterNames[i].length + 1; // parameter
1313                                                                                                                                 // name + space
1314                         }
1315
1316                         // selector
1317                         int selectorLength = methodName == null ? 0 : methodName.length;
1318                         resultLength += selectorLength;
1319
1320                         // create resulting char array
1321                         char[] result = new char[resultLength];
1322
1323                         // returned type
1324                         int index = 0;
1325                         if (includeReturnType) {
1326                                 long pos = copyType(methodSignature, lastParen + 1, result,
1327                                                 index, fullyQualifyTypeNames);
1328                                 index = (int) (pos >>> 32);
1329                                 result[index++] = ' ';
1330                         }
1331
1332                         // selector
1333                         if (methodName != null) {
1334                                 System.arraycopy(methodName, 0, result, index, selectorLength);
1335                                 index += selectorLength;
1336                         }
1337
1338                         // parameters
1339                         result[index++] = C_PARAM_START;
1340                         int sigPos = firstParen + 1;
1341                         for (int i = 0; i < paramCount; i++) {
1342                                 long pos = copyType(methodSignature, sigPos, result, index,
1343                                                 fullyQualifyTypeNames);
1344                                 index = (int) (pos >>> 32);
1345                                 sigPos = (int) pos;
1346                                 if (parameterNames != null) {
1347                                         result[index++] = ' ';
1348                                         char[] parameterName = parameterNames[i];
1349                                         int paramLength = parameterName.length;
1350                                         System.arraycopy(parameterName, 0, result, index,
1351                                                         paramLength);
1352                                         index += paramLength;
1353                                 }
1354                                 if (i != paramCount - 1) {
1355                                         result[index++] = ',';
1356                                         result[index++] = ' ';
1357                                 }
1358                         }
1359                         if (sigPos >= sigLength) {
1360                                 throw new IllegalArgumentException(); // should be on last
1361                                                                                                                 // paren
1362                         }
1363                         result[index++] = C_PARAM_END;
1364
1365                         return result;
1366                 } catch (ArrayIndexOutOfBoundsException e) {
1367                         throw new IllegalArgumentException();
1368                 }
1369         }
1370
1371         /**
1372          * Converts the given type signature to a readable string. The signature is
1373          * expected to be dot-based.
1374          * 
1375          * <p>
1376          * For example:
1377          * 
1378          * <pre>
1379          * <code>
1380          *  toString({'[', 'L', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', ';'}) -&gt; {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', '[', ']'}
1381          *  toString({'I'}) -&gt; {'i', 'n', 't'}
1382          * </code>
1383          * </pre>
1384          * 
1385          * </p>
1386          * <p>
1387          * Note: This method assumes that a type signature containing a
1388          * <code>'$'</code> is an inner type signature. While this is correct in
1389          * most cases, someone could define a non-inner type name containing a
1390          * <code>'$'</code>. Handling this correctly in all cases would have
1391          * required resolving the signature, which generally not feasible.
1392          * </p>
1393          * 
1394          * @param signature
1395          *            the type signature
1396          * @return the string representation of the type
1397          * @exception IllegalArgumentException
1398          *                if the signature is not syntactically correct
1399          * 
1400          * @since 2.0
1401          */
1402         public static char[] toCharArray(char[] signature)
1403                         throws IllegalArgumentException {
1404                 try {
1405                         int sigLength = signature.length;
1406
1407                         if (sigLength == 0 || signature[0] == C_PARAM_START) {
1408                                 return toCharArray(signature, CharOperation.NO_CHAR, null,
1409                                                 true, true);
1410                         }
1411
1412                         // compute result length
1413                         int resultLength = 0;
1414                         int index = -1;
1415                         while (signature[++index] == C_ARRAY) {
1416                                 resultLength += 2; // []
1417                         }
1418                         switch (signature[index]) {
1419                         case C_BOOLEAN:
1420                                 resultLength += BOOLEAN.length;
1421                                 break;
1422                         case C_BYTE:
1423                                 resultLength += BYTE.length;
1424                                 break;
1425                         case C_CHAR:
1426                                 resultLength += CHAR.length;
1427                                 break;
1428                         case C_DOUBLE:
1429                                 resultLength += DOUBLE.length;
1430                                 break;
1431                         case C_FLOAT:
1432                                 resultLength += FLOAT.length;
1433                                 break;
1434                         case C_INT:
1435                                 resultLength += INT.length;
1436                                 break;
1437                         case C_LONG:
1438                                 resultLength += LONG.length;
1439                                 break;
1440                         case C_SHORT:
1441                                 resultLength += SHORT.length;
1442                                 break;
1443                         case C_VOID:
1444                                 resultLength += VOID.length;
1445                                 break;
1446                         case C_RESOLVED:
1447                         case C_UNRESOLVED:
1448                                 int end = CharOperation.indexOf(C_SEMICOLON, signature, index);
1449                                 if (end == -1)
1450                                         throw new IllegalArgumentException();
1451                                 int start = index + 1;
1452                                 resultLength += end - start;
1453                                 break;
1454                         default:
1455                                 throw new IllegalArgumentException();
1456                         }
1457
1458                         char[] result = new char[resultLength];
1459                         copyType(signature, 0, result, 0, true);
1460
1461                         /**
1462                          * Converts '$' separated type signatures into '.' separated type
1463                          * signature. NOTE: This assumes that the type signature is an inner
1464                          * type signature. This is true in most cases, but someone can
1465                          * define a non-inner type name containing a '$'. However to tell
1466                          * the difference, we would have to resolve the signature, which
1467                          * cannot be done at this point.
1468                          */
1469                         CharOperation.replace(result, C_DOLLAR, C_DOT);
1470
1471                         return result;
1472                 } catch (ArrayIndexOutOfBoundsException e) {
1473                         throw new IllegalArgumentException();
1474                 }
1475         }
1476
1477         /**
1478          * Converts the given array of qualified name segments to a qualified name.
1479          * <p>
1480          * For example:
1481          * 
1482          * <pre>
1483          * <code>
1484          *  toQualifiedName({{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}) -&gt; {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}
1485          *  toQualifiedName({{'O', 'b', 'j', 'e', 'c', 't'}}) -&gt; {'O', 'b', 'j', 'e', 'c', 't'}
1486          *  toQualifiedName({{}}) -&gt; {}
1487          * </code>
1488          * </pre>
1489          * 
1490          * </p>
1491          * 
1492          * @param segments
1493          *            the list of name segments, possibly empty
1494          * @return the dot-separated qualified name, or the empty string
1495          * 
1496          * @since 2.0
1497          */
1498         public static char[] toQualifiedName(char[][] segments) {
1499                 int length = segments.length;
1500                 if (length == 0)
1501                         return CharOperation.NO_CHAR;
1502                 if (length == 1)
1503                         return segments[0];
1504
1505                 int resultLength = 0;
1506                 for (int i = 0; i < length; i++) {
1507                         resultLength += segments[i].length + 1;
1508                 }
1509                 resultLength--;
1510                 char[] result = new char[resultLength];
1511                 int index = 0;
1512                 for (int i = 0; i < length; i++) {
1513                         char[] segment = segments[i];
1514                         int segmentLength = segment.length;
1515                         System.arraycopy(segment, 0, result, index, segmentLength);
1516                         index += segmentLength;
1517                         if (i != length - 1) {
1518                                 result[index++] = C_DOT;
1519                         }
1520                 }
1521                 return result;
1522         }
1523
1524         /**
1525          * Converts the given array of qualified name segments to a qualified name.
1526          * <p>
1527          * For example:
1528          * 
1529          * <pre>
1530          * <code>
1531          *  toQualifiedName(new String[] {&quot;java&quot;, &quot;lang&quot;, &quot;Object&quot;}) -&gt; &quot;java.lang.Object&quot;
1532          *  toQualifiedName(new String[] {&quot;Object&quot;}) -&gt; &quot;Object&quot;
1533          *  toQualifiedName(new String[0]) -&gt; &quot;&quot;
1534          * </code>
1535          * </pre>
1536          * 
1537          * </p>
1538          * 
1539          * @param segments
1540          *            the list of name segments, possibly empty
1541          * @return the dot-separated qualified name, or the empty string
1542          */
1543         public static String toQualifiedName(String[] segments) {
1544                 int length = segments.length;
1545                 char[][] charArrays = new char[length][];
1546                 for (int i = 0; i < length; i++) {
1547                         charArrays[i] = segments[i].toCharArray();
1548                 }
1549                 return new String(toQualifiedName(charArrays));
1550         }
1551
1552         /**
1553          * Converts the given type signature to a readable string. The signature is
1554          * expected to be dot-based.
1555          * 
1556          * <p>
1557          * For example:
1558          * 
1559          * <pre>
1560          * <code>
1561          *  toString(&quot;[Ljava.lang.String;&quot;) -&gt; &quot;java.lang.String[]&quot;
1562          *  toString(&quot;I&quot;) -&gt; &quot;int&quot;
1563          * </code>
1564          * </pre>
1565          * 
1566          * </p>
1567          * <p>
1568          * Note: This method assumes that a type signature containing a
1569          * <code>'$'</code> is an inner type signature. While this is correct in
1570          * most cases, someone could define a non-inner type name containing a
1571          * <code>'$'</code>. Handling this correctly in all cases would have
1572          * required resolving the signature, which generally not feasible.
1573          * </p>
1574          * 
1575          * @param signature
1576          *            the type signature
1577          * @return the string representation of the type
1578          * @exception IllegalArgumentException
1579          *                if the signature is not syntactically correct
1580          */
1581         public static String toString(String signature)
1582                         throws IllegalArgumentException {
1583                 // return new String(toCharArray(signature.toCharArray()));
1584                 return "";
1585         }
1586
1587         /**
1588          * Converts the given method signature to a readable string. The method
1589          * signature is expected to be dot-based.
1590          * <p>
1591          * For example:
1592          * 
1593          * <pre>
1594          * <code>
1595          *  toString(&quot;([Ljava.lang.String;)V&quot;, &quot;main&quot;, new String[] {&quot;args&quot;}, false, true) -&gt; &quot;void main(String[] args)&quot;
1596          * </code>
1597          * </pre>
1598          * 
1599          * </p>
1600          * 
1601          * @param methodSignature
1602          *            the method signature to convert
1603          * @param methodName
1604          *            the name of the method to insert in the result, or
1605          *            <code>null</code> if no method name is to be included
1606          * @param parameterNames
1607          *            the parameter names to insert in the result, or
1608          *            <code>null</code> if no parameter names are to be included;
1609          *            if supplied, the number of parameter names must match that of
1610          *            the method signature
1611          * @param fullyQualifyTypeNames
1612          *            <code>true</code> if type names should be fully qualified,
1613          *            and <code>false</code> to use only simple names
1614          * @param includeReturnType
1615          *            <code>true</code> if the return type is to be included
1616          * @return the string representation of the method signature
1617          */
1618         public static String toString(String methodSignature, String methodName,
1619                         String[] parameterNames, boolean fullyQualifyTypeNames,
1620                         boolean includeReturnType) {
1621                 char[][] params;
1622                 if (parameterNames == null) {
1623                         params = null;
1624                 } else {
1625                         int paramLength = parameterNames.length;
1626                         params = new char[paramLength][];
1627                         for (int i = 0; i < paramLength; i++) {
1628                                 params[i] = parameterNames[i].toCharArray();
1629                         }
1630                 }
1631                 return new String(toCharArray(methodSignature.toCharArray(),
1632                                 methodName == null ? null : methodName.toCharArray(), params,
1633                                 fullyQualifyTypeNames, includeReturnType));
1634         }
1635 }