Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/jdt/core/Signature.java


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