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