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
9 * IBM Corporation - initial API and implementation
10 * IBM Corporation - added J2SE 1.5 support
11 *******************************************************************************/
12 package org.eclipse.jdt.core;
14 import java.util.ArrayList;
16 import org.eclipse.jdt.core.compiler.CharOperation;
20 * Provides methods for encoding and decoding type and method signature strings.
22 * Signatures obtained from parsing source (".java") files differ subtly from
23 * ones obtained from pre-compiled binary (".class") files in class names are
24 * usually left unresolved in the former. For example, the normal resolved form
25 * of the type "String" embeds the class's package name ("Ljava.lang.String;"
26 * or "Ljava/lang/String;"), whereas the unresolved form contains only what is
30 * Generic types introduce to the Java language in J2SE 1.5 add three new
31 * facets to signatures: type variables, parameterized types with type arguments,
32 * and formal type parameters. <it>Rich</it> signatures containing these facets
33 * only occur when dealing with code that makes overt use of the new language
34 * features. All other code, and certainly all Java code written or compiled
35 * with J2SE 1.4 or earlier, involved only <it>simple</it> signatures.
38 * The syntax for a type signature is:
50 * | "T" + Identifier + ";" // type variable
51 * | "[" + TypeSignature // array X[]
52 * | ResolvedClassTypeSignature
53 * | UnresolvedClassTypeSignature
55 * ResolvedClassTypeSignature ::= // resolved named type (in compiled code)
56 * "L" + Identifier + OptionalTypeArguments
57 * ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
59 * UnresolvedClassTypeSignature ::= // unresolved named type (in source code)
60 * "Q" + Identifier + OptionalTypeArguments
61 * ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
63 * OptionalTypeArguments ::=
64 * "<" + TypeArgument+ + ">"
70 * | "+" TypeSignature // wildcard ? extends X
71 * | "-" TypeSignature // wildcard ? super X
77 * <li><code>"[[I"</code> denotes <code>int[][]</code></li>
78 * <li><code>"Ljava.lang.String;"</code> denotes <code>java.lang.String</code> in compiled code</li>
79 * <li><code>"QString;"</code> denotes <code>String</code> in source code</li>
80 * <li><code>"Qjava.lang.String;"</code> denotes <code>java.lang.String</code> in source code</li>
81 * <li><code>"[QString;"</code> denotes <code>String[]</code> in source code</li>
82 * <li><code>"QMap<QString;*>;"</code> denotes <code>Map<String,?></code> in source code</li>
83 * <li><code>"Qjava.util.List<TV;>;"</code> denotes <code>java.util.List<V></code> in source code</li>
87 * The syntax for a method signature is:
89 * MethodSignature ::= "(" + ParamTypeSignature* + ")" + ReturnTypeSignature
90 * ParamTypeSignature ::= TypeSignature
91 * ReturnTypeSignature ::= TypeSignature
96 * <li><code>"()I"</code> denotes <code>int foo()</code></li>
97 * <li><code>"([Ljava.lang.String;)V"</code> denotes <code>void foo(java.lang.String[])</code> in compiled code</li>
98 * <li><code>"(QString;)QObject;"</code> denotes <code>Object foo(String)</code> in source code</li>
102 * The syntax for a formal type parameter signature is:
104 * FormalTypeParameterSignature ::=
105 * TypeVariableName + OptionalClassBound + InterfaceBound*
106 * TypeVariableName ::= Identifier
107 * OptionalClassBound ::=
109 * | ":" + TypeSignature
111 * ":" + TypeSignature
116 * <li><code>"X:"</code> denotes <code>X</code></li>
117 * <li><code>"X:QReader;"</code> denotes <code>X extends Reader</code> in source code</li>
118 * <li><code>"X:QReader;:QSerializable;"</code> denotes <code>X extends Reader & Serializable</code> in source code</li>
122 * This class provides static methods and constants only; it is not intended to be
123 * instantiated or subclassed by clients.
126 public final class Signature {
129 * Character constant indicating the primitive type boolean in a signature.
130 * Value is <code>'Z'</code>.
132 public static final char C_BOOLEAN = 'Z';
135 * Character constant indicating the primitive type byte in a signature.
136 * Value is <code>'B'</code>.
138 public static final char C_BYTE = 'B';
141 * Character constant indicating the primitive type char in a signature.
142 * Value is <code>'C'</code>.
144 public static final char C_CHAR = 'C';
147 * Character constant indicating the primitive type double in a signature.
148 * Value is <code>'D'</code>.
150 public static final char C_DOUBLE = 'D';
153 * Character constant indicating the primitive type float in a signature.
154 * Value is <code>'F'</code>.
156 public static final char C_FLOAT = 'F';
159 * Character constant indicating the primitive type int in a signature.
160 * Value is <code>'I'</code>.
162 public static final char C_INT = 'I';
165 * Character constant indicating the semicolon in a signature.
166 * Value is <code>';'</code>.
168 public static final char C_SEMICOLON = ';';
171 * Character constant indicating the colon in a signature.
172 * Value is <code>':'</code>.
175 public static final char C_COLON = ':';
178 * Character constant indicating the primitive type long in a signature.
179 * Value is <code>'J'</code>.
181 public static final char C_LONG = 'J';
184 * Character constant indicating the primitive type short in a signature.
185 * Value is <code>'S'</code>.
187 public static final char C_SHORT = 'S';
190 * Character constant indicating result type void in a signature.
191 * Value is <code>'V'</code>.
193 public static final char C_VOID = 'V';
196 * Character constant indicating the start of a resolved type variable in a
197 * signature. Value is <code>'T'</code>.
200 public static final char C_TYPE_VARIABLE = 'T';
203 * Character constant indicating an unbound wildcard type argument
205 * Value is <code>'*'</code>.
208 public static final char C_STAR = '*';
211 * Character constant indicating a bound wildcard type argument
212 * in a signature with extends clause.
213 * Value is <code>'+'</code>.
216 public static final char C_EXTENDS = '+';
219 * Character constant indicating a bound wildcard type argument
220 * in a signature with super clause.
221 * Value is <code>'-'</code>.
224 public static final char C_SUPER = '-';
227 * Character constant indicating the dot in a signature.
228 * Value is <code>'.'</code>.
230 public static final char C_DOT = '.';
233 * Character constant indicating the dollar in a signature.
234 * Value is <code>'$'</code>.
236 public static final char C_DOLLAR = '$';
239 * Character constant indicating an array type in a signature.
240 * Value is <code>'['</code>.
242 public static final char C_ARRAY = '[';
245 * Character constant indicating the start of a resolved, named type in a
246 * signature. Value is <code>'L'</code>.
248 public static final char C_RESOLVED = 'L';
251 * Character constant indicating the start of an unresolved, named type in a
252 * signature. Value is <code>'Q'</code>.
254 public static final char C_UNRESOLVED = 'Q';
257 * Character constant indicating the end of a named type in a signature.
258 * Value is <code>';'</code>.
260 public static final char C_NAME_END = ';';
263 * Character constant indicating the start of a parameter type list in a
264 * signature. Value is <code>'('</code>.
266 public static final char C_PARAM_START = '(';
269 * Character constant indicating the end of a parameter type list in a
270 * signature. Value is <code>')'</code>.
272 public static final char C_PARAM_END = ')';
275 * Character constant indicating the start of a formal type parameter
276 * (or type argument) list in a signature. Value is <code>'<'</code>.
279 public static final char C_GENERIC_START = '<';
282 * Character constant indicating the end of a generic type list in a
283 * signature. Value is <code>'%gt;'</code>.
286 public static final char C_GENERIC_END = '>';
289 * String constant for the signature of the primitive type boolean.
290 * Value is <code>"Z"</code>.
292 public static final String SIG_BOOLEAN = "Z"; //$NON-NLS-1$
295 * String constant for the signature of the primitive type byte.
296 * Value is <code>"B"</code>.
298 public static final String SIG_BYTE = "B"; //$NON-NLS-1$
301 * String constant for the signature of the primitive type char.
302 * Value is <code>"C"</code>.
304 public static final String SIG_CHAR = "C"; //$NON-NLS-1$
307 * String constant for the signature of the primitive type double.
308 * Value is <code>"D"</code>.
310 public static final String SIG_DOUBLE = "D"; //$NON-NLS-1$
313 * String constant for the signature of the primitive type float.
314 * Value is <code>"F"</code>.
316 public static final String SIG_FLOAT = "F"; //$NON-NLS-1$
319 * String constant for the signature of the primitive type int.
320 * Value is <code>"I"</code>.
322 public static final String SIG_INT = "I"; //$NON-NLS-1$
325 * String constant for the signature of the primitive type long.
326 * Value is <code>"J"</code>.
328 public static final String SIG_LONG = "J"; //$NON-NLS-1$
331 * String constant for the signature of the primitive type short.
332 * Value is <code>"S"</code>.
334 public static final String SIG_SHORT = "S"; //$NON-NLS-1$
336 /** String constant for the signature of result type void.
337 * Value is <code>"V"</code>.
339 public static final String SIG_VOID = "V"; //$NON-NLS-1$
343 * Kind constant for a class type signature.
344 * @see #getTypeSignatureKind(String)
347 public static int CLASS_TYPE_SIGNATURE = 1;
350 * Kind constant for a base (primitive or void) type signature.
351 * @see #getTypeSignatureKind(String)
354 public static int BASE_TYPE_SIGNATURE = 2;
357 * Kind constant for a type variable signature.
358 * @see #getTypeSignatureKind(String)
361 public static int TYPE_VARIABLE_SIGNATURE = 3;
364 * Kind constant for an array type signature.
365 * @see #getTypeSignatureKind(String)
368 public static int ARRAY_TYPE_SIGNATURE = 4;
370 private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$
371 private static final char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
372 private static final char[] CHAR = "char".toCharArray(); //$NON-NLS-1$
373 private static final char[] DOUBLE = "double".toCharArray(); //$NON-NLS-1$
374 private static final char[] FLOAT = "float".toCharArray(); //$NON-NLS-1$
375 private static final char[] INT = "int".toCharArray(); //$NON-NLS-1$
376 private static final char[] LONG = "long".toCharArray(); //$NON-NLS-1$
377 private static final char[] SHORT = "short".toCharArray(); //$NON-NLS-1$
378 private static final char[] VOID = "void".toCharArray(); //$NON-NLS-1$
379 private static final char[] EXTENDS = "extends".toCharArray(); //$NON-NLS-1$
380 private static final char[] SUPER = "super".toCharArray(); //$NON-NLS-1$
382 private static final String EMPTY = new String(CharOperation.NO_CHAR);
384 private Signature() {
388 private static int checkName(char[] name, char[] typeName, int pos, int length) {
389 if (CharOperation.fragmentEquals(name, typeName, pos, true)) {
391 if (pos == length) return pos;
392 char currentChar = typeName[pos];
393 switch (currentChar) {
402 if (Character.isWhitespace(currentChar))
411 * Creates a new type signature with the given amount of array nesting added
412 * to the given type signature.
414 * @param typeSignature the type signature
415 * @param arrayCount the desired number of levels of array nesting
416 * @return the encoded array type signature
420 public static char[] createArraySignature(char[] typeSignature, int arrayCount) {
421 if (arrayCount == 0) return typeSignature;
422 int sigLength = typeSignature.length;
423 char[] result = new char[arrayCount + sigLength];
424 for (int i = 0; i < arrayCount; i++) {
427 System.arraycopy(typeSignature, 0, result, arrayCount, sigLength);
431 * Creates a new type signature with the given amount of array nesting added
432 * to the given type signature.
434 * @param typeSignature the type signature
435 * @param arrayCount the desired number of levels of array nesting
436 * @return the encoded array type signature
438 public static String createArraySignature(String typeSignature, int arrayCount) {
439 return new String(createArraySignature(typeSignature.toCharArray(), arrayCount));
443 * Creates a method signature from the given parameter and return type
444 * signatures. The encoded method signature is dot-based.
446 * @param parameterTypes the list of parameter type signatures
447 * @param returnType the return type signature
448 * @return the encoded method signature
452 public static char[] createMethodSignature(char[][] parameterTypes, char[] returnType) {
453 int parameterTypesLength = parameterTypes.length;
454 int parameterLength = 0;
455 for (int i = 0; i < parameterTypesLength; i++) {
456 parameterLength += parameterTypes[i].length;
459 int returnTypeLength = returnType.length;
460 char[] result = new char[1 + parameterLength + 1 + returnTypeLength];
461 result[0] = C_PARAM_START;
463 for (int i = 0; i < parameterTypesLength; i++) {
464 char[] parameterType = parameterTypes[i];
465 int length = parameterType.length;
466 System.arraycopy(parameterType, 0, result, index, length);
469 result[index] = C_PARAM_END;
470 System.arraycopy(returnType, 0, result, index+1, returnTypeLength);
475 * Creates a method signature from the given parameter and return type
476 * signatures. The encoded method signature is dot-based. This method
478 * <code>createMethodSignature(parameterTypes, returnType)</code>.
480 * @param parameterTypes the list of parameter type signatures
481 * @param returnType the return type signature
482 * @return the encoded method signature
483 * @see Signature#createMethodSignature(char[][], char[])
485 public static String createMethodSignature(String[] parameterTypes, String returnType) {
486 int parameterTypesLenth = parameterTypes.length;
487 char[][] parameters = new char[parameterTypesLenth][];
488 for (int i = 0; i < parameterTypesLenth; i++) {
489 parameters[i] = parameterTypes[i].toCharArray();
491 return new String(createMethodSignature(parameters, returnType.toCharArray()));
495 * Creates a new type parameter signature with the given name and bounds.
497 * @param typeParameterName the type parameter name
498 * @param boundSignatures the signatures of associated bounds or empty array if none
499 * @return the encoded type parameter signature
503 public static char[] createTypeParameterSignature(char[] typeParameterName, char[][] boundSignatures) {
504 int length = boundSignatures.length;
506 return CharOperation.append(typeParameterName, C_COLON); // param signature with no bounds still gets trailing colon
509 for (int i = 0; i < length; i++) {
510 boundsSize += boundSignatures[i].length + 1;
512 int nameLength = typeParameterName.length;
513 char[] result = new char[nameLength + boundsSize];
514 System.arraycopy(typeParameterName, 0, result, 0, nameLength);
515 int index = nameLength;
516 for (int i = 0; i < length; i++) {
517 result[index++] = C_COLON;
518 int boundLength = boundSignatures[i].length;
519 System.arraycopy(boundSignatures[i], 0, result, index, boundLength);
520 index += boundLength;
526 * Creates a new type parameter signature with the given name and bounds.
528 * @param typeParameterName the type parameter name
529 * @param boundSignatures the signatures of associated bounds or empty array if none
530 * @return the encoded type parameter signature
534 public static String createTypeParameterSignature(String typeParameterName, String[] boundSignatures) {
535 int length = boundSignatures.length;
536 char[][] boundSignatureChars = new char[length][];
537 for (int i = 0; i < length; i++) {
538 boundSignatureChars[i] = boundSignatures[i].toCharArray();
540 return new String(createTypeParameterSignature(typeParameterName.toCharArray(), boundSignatureChars));
544 * Creates a new type signature from the given type name encoded as a character
545 * array. The type name may contain primitive types, array types or parameterized types.
546 * This method is equivalent to
547 * <code>createTypeSignature(new String(typeName),isResolved)</code>, although
548 * more efficient for callers with character arrays rather than strings. If the
549 * type name is qualified, then it is expected to be dot-based.
551 * @param typeName the possibly qualified type name
552 * @param isResolved <code>true</code> if the type name is to be considered
553 * resolved (for example, a type name from a binary class file), and
554 * <code>false</code> if the type name is to be considered unresolved
555 * (for example, a type name found in source code)
556 * @return the encoded type signature
557 * @see #createTypeSignature(java.lang.String,boolean)
559 public static String createTypeSignature(char[] typeName, boolean isResolved) {
560 return new String(createCharArrayTypeSignature(typeName, isResolved));
564 * Creates a new type signature from the given type name encoded as a character
565 * array. The type name may contain primitive types or array types or parameterized types.
566 * This method is equivalent to
567 * <code>createTypeSignature(new String(typeName),isResolved).toCharArray()</code>,
568 * although more efficient for callers with character arrays rather than strings.
569 * If the type name is qualified, then it is expected to be dot-based.
571 * @param typeName the possibly qualified type name
572 * @param isResolved <code>true</code> if the type name is to be considered
573 * resolved (for example, a type name from a binary class file), and
574 * <code>false</code> if the type name is to be considered unresolved
575 * (for example, a type name found in source code)
576 * @return the encoded type signature
577 * @see #createTypeSignature(java.lang.String,boolean)
581 public static char[] createCharArrayTypeSignature(char[] typeName, boolean isResolved) {
582 if (typeName == null) throw new IllegalArgumentException("null"); //$NON-NLS-1$
583 int length = typeName.length;
584 if (length == 0) throw new IllegalArgumentException(new String(typeName));
585 StringBuffer buffer = new StringBuffer(5);
586 int pos = encodeTypeSignature(typeName, 0, isResolved, length, buffer);
587 pos = consumeWhitespace(typeName, pos, length);
588 if (pos < length) throw new IllegalArgumentException(new String(typeName));
589 char[] result = new char[length = buffer.length()];
590 buffer.getChars(0, length, result, 0);
593 private static int consumeWhitespace(char[] typeName, int pos, int length) {
594 while (pos < length) {
595 char currentChar = typeName[pos];
596 if (currentChar != ' ' && !CharOperation.isWhitespace(currentChar)) {
603 private static int encodeQualifiedName(char[] typeName, int pos, int length, StringBuffer buffer) {
605 char lastAppendedChar = 0;
606 nameLoop: while (pos < length) {
607 char currentChar = typeName[pos];
608 switch (currentChar) {
615 buffer.append(C_DOT);
616 lastAppendedChar = C_DOT;
620 if (currentChar == ' ' || Character.isWhitespace(currentChar)) {
621 if (lastAppendedChar == C_DOT) { // allow spaces after a dot
622 pos = consumeWhitespace(typeName, pos, length) - 1; // will be incremented
625 // allow spaces before a dot
626 int checkPos = checkNextChar(typeName, '.', pos, length, true);
628 buffer.append(C_DOT); // process dot immediately to avoid one iteration
629 lastAppendedChar = C_DOT;
636 buffer.append(currentChar);
637 lastAppendedChar = currentChar;
643 if (count == 0) throw new IllegalArgumentException(new String(typeName));
647 private static int encodeArrayDimension(char[] typeName, int pos, int length, StringBuffer buffer) {
649 while (pos < length && (checkPos = checkNextChar(typeName, '[', pos, length, true)) > 0) {
650 pos = checkNextChar(typeName, ']', checkPos, length, false);
651 buffer.append(C_ARRAY);
655 private static int checkArrayDimension(char[] typeName, int pos, int length) {
656 int genericBalance = 0;
657 while (pos < length) {
658 switch(typeName[pos]) {
663 if (genericBalance == 0) return -1;
666 if (genericBalance == 0) return -1;
670 if (genericBalance == 0) {
678 private static int checkNextChar(char[] typeName, char expectedChar, int pos, int length, boolean isOptional) {
679 pos = consumeWhitespace(typeName, pos, length);
680 if (pos < length && typeName[pos] == expectedChar)
682 if (!isOptional) throw new IllegalArgumentException(new String(typeName));
686 private static int encodeTypeSignature(char[] typeName, int start, boolean isResolved, int length, StringBuffer buffer) {
688 pos = consumeWhitespace(typeName, pos, length);
689 if (pos >= length) throw new IllegalArgumentException(new String(typeName));
691 char currentChar = typeName[pos];
692 switch (currentChar) {
695 checkPos = checkName(BOOLEAN, typeName, pos, length);
697 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
698 buffer.append(C_BOOLEAN);
701 checkPos = checkName(BYTE, typeName, pos, length);
703 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
704 buffer.append(C_BYTE);
709 checkPos = checkName(CHAR, typeName, pos, length);
711 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
712 buffer.append(C_CHAR);
717 checkPos = checkName(DOUBLE, typeName, pos, length);
719 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
720 buffer.append(C_DOUBLE);
725 checkPos = checkName(FLOAT, typeName, pos, length);
727 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
728 buffer.append(C_FLOAT);
733 checkPos = checkName(INT, typeName, pos, length);
735 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
736 buffer.append(C_INT);
741 checkPos = checkName(LONG, typeName, pos, length);
743 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
744 buffer.append(C_LONG);
749 checkPos = checkName(SHORT, typeName, pos, length);
751 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
752 buffer.append(C_SHORT);
757 checkPos = checkName(VOID, typeName, pos, length);
759 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
760 buffer.append(C_VOID);
766 pos = consumeWhitespace(typeName, pos+1, length);
767 checkPos = checkName(EXTENDS, typeName, pos, length);
769 buffer.append(C_EXTENDS);
770 pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
773 checkPos = checkName(SUPER, typeName, pos, length);
775 buffer.append(C_SUPER);
776 pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
779 buffer.append(C_STAR);
782 // non primitive type
783 checkPos = checkArrayDimension(typeName, pos, length);
786 end = encodeArrayDimension(typeName, checkPos, length, buffer);
790 buffer.append(isResolved ? C_RESOLVED : C_UNRESOLVED);
791 while (true) { // loop on qualifiedName[<args>][.qualifiedName[<args>]*
792 pos = encodeQualifiedName(typeName, pos, length, buffer);
793 checkPos = checkNextChar(typeName, '<', pos, length, true);
795 buffer.append(C_GENERIC_START);
796 pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
797 while ((checkPos = checkNextChar(typeName, ',', pos, length, true)) > 0) {
798 pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
800 pos = checkNextChar(typeName, '>', pos, length, false);
801 buffer.append(C_GENERIC_END);
803 checkPos = checkNextChar(typeName, '.', pos, length, true);
805 buffer.append(C_DOT);
811 buffer.append(C_NAME_END);
812 if (end > 0) pos = end; // skip array dimension which were preprocessed
817 * Creates a new type signature from the given type name. If the type name is qualified,
818 * then it is expected to be dot-based. The type name may contain primitive
819 * types or array types. However, parameterized types are not supported.
824 * createTypeSignature("int", hucairz) -> "I"
825 * createTypeSignature("java.lang.String", true) -> "Ljava.lang.String;"
826 * createTypeSignature("String", false) -> "QString;"
827 * createTypeSignature("java.lang.String", false) -> "Qjava.lang.String;"
828 * createTypeSignature("int []", false) -> "[I"
833 * @param typeName the possibly qualified type name
834 * @param isResolved <code>true</code> if the type name is to be considered
835 * resolved (for example, a type name from a binary class file), and
836 * <code>false</code> if the type name is to be considered unresolved
837 * (for example, a type name found in source code)
838 * @return the encoded type signature
840 public static String createTypeSignature(String typeName, boolean isResolved) {
841 return createTypeSignature(typeName == null ? null : typeName.toCharArray(), isResolved);
845 * Returns the array count (array nesting depth) of the given type signature.
847 * @param typeSignature the type signature
848 * @return the array nesting depth, or 0 if not an array
849 * @exception IllegalArgumentException if the signature is not syntactically
854 public static int getArrayCount(char[] typeSignature) throws IllegalArgumentException {
857 while (typeSignature[count] == C_ARRAY) {
861 } catch (ArrayIndexOutOfBoundsException e) { // signature is syntactically incorrect if last character is C_ARRAY
862 throw new IllegalArgumentException();
866 * Returns the array count (array nesting depth) of the given type signature.
868 * @param typeSignature the type signature
869 * @return the array nesting depth, or 0 if not an array
870 * @exception IllegalArgumentException if the signature is not syntactically
873 public static int getArrayCount(String typeSignature) throws IllegalArgumentException {
874 return getArrayCount(typeSignature.toCharArray());
877 * Returns the type signature without any array nesting.
882 * getElementType({'[', '[', 'I'}) --> {'I'}.
887 * @param typeSignature the type signature
888 * @return the type signature without arrays
889 * @exception IllegalArgumentException if the signature is not syntactically
894 public static char[] getElementType(char[] typeSignature) throws IllegalArgumentException {
895 int count = getArrayCount(typeSignature);
896 if (count == 0) return typeSignature;
897 int length = typeSignature.length;
898 char[] result = new char[length-count];
899 System.arraycopy(typeSignature, count, result, 0, length-count);
903 * Returns the type signature without any array nesting.
908 * getElementType("[[I") --> "I".
913 * @param typeSignature the type signature
914 * @return the type signature without arrays
915 * @exception IllegalArgumentException if the signature is not syntactically
918 public static String getElementType(String typeSignature) throws IllegalArgumentException {
919 return new String(getElementType(typeSignature.toCharArray()));
922 * Returns the number of parameter types in the given method signature.
924 * @param methodSignature the method signature
925 * @return the number of parameters
926 * @exception IllegalArgumentException if the signature is not syntactically
930 public static int getParameterCount(char[] methodSignature) throws IllegalArgumentException {
933 int i = CharOperation.indexOf(C_PARAM_START, methodSignature);
935 throw new IllegalArgumentException();
940 if (methodSignature[i] == C_PARAM_END) {
943 int e= scanTypeSignature(methodSignature, i);
945 throw new IllegalArgumentException();
951 } catch (ArrayIndexOutOfBoundsException e) {
952 throw new IllegalArgumentException();
957 * Returns the kind of type signature encoded by the given string.
959 * @param typeSignature the type signature string
960 * @return the kind of type signature; one of the kind constants:
961 * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
962 * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}
963 * @exception IllegalArgumentException if this is not a type signature
966 public static int getTypeSignatureKind(char[] typeSignature) {
967 // need a minimum 1 char
968 if (typeSignature.length < 1) {
969 throw new IllegalArgumentException();
971 char c = typeSignature[0];
974 return ARRAY_TYPE_SIGNATURE;
977 return CLASS_TYPE_SIGNATURE;
978 case C_TYPE_VARIABLE :
979 return TYPE_VARIABLE_SIGNATURE;
989 return BASE_TYPE_SIGNATURE;
991 throw new IllegalArgumentException();
996 * Returns the kind of type signature encoded by the given string.
998 * @param typeSignature the type signature string
999 * @return the kind of type signature; one of the kind constants:
1000 * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
1001 * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}
1002 * @exception IllegalArgumentException if this is not a type signature
1005 public static int getTypeSignatureKind(String typeSignature) {
1006 // need a minimum 1 char
1007 if (typeSignature.length() < 1) {
1008 throw new IllegalArgumentException();
1010 char c = typeSignature.charAt(0);
1013 return ARRAY_TYPE_SIGNATURE;
1016 return CLASS_TYPE_SIGNATURE;
1017 case C_TYPE_VARIABLE :
1018 return TYPE_VARIABLE_SIGNATURE;
1028 return BASE_TYPE_SIGNATURE;
1030 throw new IllegalArgumentException();
1035 * Scans the given string for a type signature starting at the given index
1036 * and returns the index of the last character.
1039 * | BaseTypeSignature
1040 * | ArrayTypeSignature
1041 * | ClassTypeSignature
1042 * | TypeVariableSignature
1045 * @param string the signature string
1046 * @param start the 0-based character index of the first character
1047 * @return the 0-based character index of the last character
1048 * @exception IllegalArgumentException if this is not a type signature
1049 * @see #appendTypeSignature(char[], int, boolean, StringBuffer)
1051 private static int scanTypeSignature(char[] string, int start) {
1052 // need a minimum 1 char
1053 if (start >= string.length) {
1054 throw new IllegalArgumentException();
1056 char c = string[start];
1059 return scanArrayTypeSignature(string, start);
1062 return scanClassTypeSignature(string, start);
1063 case C_TYPE_VARIABLE :
1064 return scanTypeVariableSignature(string, start);
1074 return scanBaseTypeSignature(string, start);
1076 throw new IllegalArgumentException();
1081 * Scans the given string for a base type signature starting at the given index
1082 * and returns the index of the last character.
1084 * BaseTypeSignature:
1085 * <b>B</b> | <b>C</b> | <b>D</b> | <b>F</b> | <b>I</b>
1086 * | <b>J</b> | <b>S</b> | <b>V</b> | <b>Z</b>
1088 * Note that although the base type "V" is only allowed in method return types,
1089 * there is no syntactic ambiguity. This method will accept them anywhere
1090 * without complaint.
1092 * @param string the signature string
1093 * @param start the 0-based character index of the first character
1094 * @return the 0-based character index of the last character
1095 * @exception IllegalArgumentException if this is not a base type signature
1097 private static int scanBaseTypeSignature(char[] string, int start) {
1098 // need a minimum 1 char
1099 if (start >= string.length) {
1100 throw new IllegalArgumentException();
1102 char c = string[start];
1103 if ("BCDFIJSVZ".indexOf(c) >= 0) { //$NON-NLS-1$
1106 throw new IllegalArgumentException();
1111 * Scans the given string for an array type signature starting at the given
1112 * index and returns the index of the last character.
1114 * ArrayTypeSignature:
1115 * <b>[</b> TypeSignature
1118 * @param string the signature string
1119 * @param start the 0-based character index of the first character
1120 * @return the 0-based character index of the last character
1121 * @exception IllegalArgumentException if this is not an array type signature
1122 * @see #appendArrayTypeSignature(char[], int, boolean, StringBuffer)
1124 private static int scanArrayTypeSignature(char[] string, int start) {
1125 // need a minimum 2 char
1126 if (start >= string.length - 1) {
1127 throw new IllegalArgumentException();
1129 char c = string[start];
1130 if (c != C_ARRAY) { //$NON-NLS-1$
1131 throw new IllegalArgumentException();
1133 return scanTypeSignature(string, start + 1);
1137 * Scans the given string for a type variable signature starting at the given
1138 * index and returns the index of the last character.
1140 * TypeVariableSignature:
1141 * <b>T</b> Identifier <b>;</b>
1144 * @param string the signature string
1145 * @param start the 0-based character index of the first character
1146 * @return the 0-based character index of the last character
1147 * @exception IllegalArgumentException if this is not a type variable signature
1149 private static int scanTypeVariableSignature(char[] string, int start) {
1150 // need a minimum 3 chars "Tx;"
1151 if (start >= string.length - 2) {
1152 throw new IllegalArgumentException();
1154 // must start in "T"
1155 char c = string[start];
1156 if (c != C_TYPE_VARIABLE) {
1157 throw new IllegalArgumentException();
1159 int id = scanIdentifier(string, start + 1);
1161 if (c == C_SEMICOLON) {
1164 throw new IllegalArgumentException();
1169 * Scans the given string for an identifier starting at the given
1170 * index and returns the index of the last character.
1171 * Stop characters are: ";", ":", "<", ">", "/", ".".
1173 * @param string the signature string
1174 * @param start the 0-based character index of the first character
1175 * @return the 0-based character index of the last character
1176 * @exception IllegalArgumentException if this is not an identifier
1178 private static int scanIdentifier(char[] string, int start) {
1179 // need a minimum 1 char
1180 if (start >= string.length) {
1181 throw new IllegalArgumentException();
1186 if (c == '<' || c == '>' || c == ':' || c == ';' || c == '.' || c == '/') {
1190 if (p == string.length) {
1197 * Scans the given string for a class type signature starting at the given
1198 * index and returns the index of the last character.
1200 * ClassTypeSignature:
1201 * { <b>L</b> | <b>Q</b> } Identifier
1202 * { { <b>/</b> | <b>.</b> Identifier [ <b><</b> TypeArgumentSignature* <b>></b> ] }
1205 * Note that although all "/"-identifiers most come before "."-identifiers,
1206 * there is no syntactic ambiguity. This method will accept them without
1209 * @param string the signature string
1210 * @param start the 0-based character index of the first character
1211 * @return the 0-based character index of the last character
1212 * @exception IllegalArgumentException if this is not a class type signature
1213 * @see #appendClassTypeSignature(char[], int, boolean, StringBuffer)
1215 private static int scanClassTypeSignature(char[] string, int start) {
1216 // need a minimum 3 chars "Lx;"
1217 if (start >= string.length - 2) {
1218 throw new IllegalArgumentException();
1220 // must start in "L" or "Q"
1221 char c = string[start];
1222 if (c != C_RESOLVED && c != C_UNRESOLVED) {
1227 if (p >= string.length) {
1228 throw new IllegalArgumentException();
1231 if (c == C_SEMICOLON) {
1234 } else if (c == C_GENERIC_START) {
1235 int e = scanTypeArgumentSignatures(string, p);
1237 } else if (c == C_DOT || c == '/') {
1238 int id = scanIdentifier(string, p + 1);
1246 * Scans the given string for a list of type argument signatures starting at
1247 * the given index and returns the index of the last character.
1249 * TypeArgumentSignatures:
1250 * <b><</b> TypeArgumentSignature* <b>></b>
1252 * Note that although there is supposed to be at least one type argument, there
1253 * is no syntactic ambiguity if there are none. This method will accept zero
1254 * type argument signatures without complaint.
1256 * @param string the signature string
1257 * @param start the 0-based character index of the first character
1258 * @return the 0-based character index of the last character
1259 * @exception IllegalArgumentException if this is not a list of type arguments
1261 * @see #appendTypeArgumentSignatures(char[], int, boolean, StringBuffer)
1263 private static int scanTypeArgumentSignatures(char[] string, int start) {
1264 // need a minimum 2 char "<>"
1265 if (start >= string.length - 1) {
1266 throw new IllegalArgumentException();
1268 char c = string[start];
1269 if (c != C_GENERIC_START) {
1270 throw new IllegalArgumentException();
1274 if (p >= string.length) {
1275 throw new IllegalArgumentException();
1278 if (c == C_GENERIC_END) {
1281 int e = scanTypeArgumentSignature(string, p);
1287 * Scans the given string for a type argument signature starting at the given
1288 * index and returns the index of the last character.
1290 * TypeArgumentSignature:
1292 * | <b>+</b> TypeSignature
1293 * | <b>-</b> TypeSignature
1296 * Note that although base types are not allowed in type arguments, there is
1297 * no syntactic ambiguity. This method will accept them without complaint.
1299 * @param string the signature string
1300 * @param start the 0-based character index of the first character
1301 * @return the 0-based character index of the last character
1302 * @exception IllegalArgumentException if this is not a type argument signature
1303 * @see #appendTypeArgumentSignature(char[], int, boolean, StringBuffer)
1305 private static int scanTypeArgumentSignature(char[] string, int start) {
1306 // need a minimum 1 char
1307 if (start >= string.length) {
1308 throw new IllegalArgumentException();
1310 char c = string[start];
1314 if (c == '+' || c == '-') {
1315 return scanTypeSignature(string, start + 1);
1317 return scanTypeSignature(string, start);
1322 * Returns the number of parameter types in the given method signature.
1324 * @param methodSignature the method signature
1325 * @return the number of parameters
1326 * @exception IllegalArgumentException if the signature is not syntactically
1329 public static int getParameterCount(String methodSignature) throws IllegalArgumentException {
1330 return getParameterCount(methodSignature.toCharArray());
1334 * Extracts the parameter type signatures from the given method signature.
1335 * The method signature is expected to be dot-based.
1337 * @param methodSignature the method signature
1338 * @return the list of parameter type signatures
1339 * @exception IllegalArgumentException if the signature is syntactically
1344 public static char[][] getParameterTypes(char[] methodSignature) throws IllegalArgumentException {
1346 int count = getParameterCount(methodSignature);
1347 char[][] result = new char[count][];
1351 int i = CharOperation.indexOf(C_PARAM_START, methodSignature);
1353 throw new IllegalArgumentException();
1359 if (methodSignature[i] == C_PARAM_END) {
1362 int e = scanTypeSignature(methodSignature, i);
1364 throw new IllegalArgumentException();
1366 result[t] = CharOperation.subarray(methodSignature, i, e + 1);
1370 } catch (ArrayIndexOutOfBoundsException e) {
1371 throw new IllegalArgumentException();
1376 * Extracts the parameter type signatures from the given method signature.
1377 * The method signature is expected to be dot-based.
1379 * @param methodSignature the method signature
1380 * @return the list of parameter type signatures
1381 * @exception IllegalArgumentException if the signature is syntactically
1384 public static String[] getParameterTypes(String methodSignature) throws IllegalArgumentException {
1385 char[][] parameterTypes = getParameterTypes(methodSignature.toCharArray());
1386 return CharOperation.toStrings(parameterTypes);
1390 * Extracts the thrown exception type signatures from the given method signature if any
1391 * The method signature is expected to be dot-based.
1393 * @param methodSignature the method signature
1394 * @return the list of thrown exception type signatures
1395 * @exception IllegalArgumentException if the signature is syntactically
1398 public static String[] getThrownExceptionTypes(String methodSignature) throws IllegalArgumentException {
1399 char[][] parameterTypes = getThrownExceptionTypes(methodSignature.toCharArray());
1400 return CharOperation.toStrings(parameterTypes);
1404 * Extracts the thrown exception type signatures from the given method signature if any
1405 * The method signature is expected to be dot-based.
1407 * @param methodSignature the method signature
1408 * @return the list of thrown exception type signatures
1409 * @exception IllegalArgumentException if the signature is syntactically
1412 public static char[][] getThrownExceptionTypes(char[] methodSignature) throws IllegalArgumentException {
1413 // skip type parameters
1414 int paren = CharOperation.lastIndexOf(C_PARAM_END, methodSignature);
1416 throw new IllegalArgumentException();
1418 // ignore return type
1419 int exceptionStart = scanTypeSignature(methodSignature, paren+1) + 1;
1420 int length = methodSignature.length;
1421 if (exceptionStart == length) return CharOperation.NO_CHAR_CHAR;
1423 ArrayList exceptionList = new ArrayList(1);
1424 int i = exceptionStart;
1425 while (i < length) {
1426 i = scanTypeSignature(methodSignature, i) + 1;
1427 exceptionList.add(CharOperation.subarray(methodSignature, exceptionStart,i));
1431 exceptionList.toArray(result = new char[exceptionList.size()][]);
1436 * Extracts the type argument signatures from the given type signature.
1437 * Returns an empty array if the type signature is not a parameterized type signature.
1439 * @param parameterizedTypeSignature the parameterized type signature
1440 * @return the signatures of the type arguments
1441 * @exception IllegalArgumentException if the signature is syntactically incorrect
1445 public static char[][] getTypeArguments(char[] parameterizedTypeSignature) throws IllegalArgumentException {
1446 int length = parameterizedTypeSignature.length;
1447 if (length < 2 || parameterizedTypeSignature[length-2] != C_GENERIC_END)
1448 // cannot have type arguments otherwise signature would end by ">;"
1449 return CharOperation.NO_CHAR_CHAR;
1450 int count = 1; // start to count generic end/start peers
1451 int start = length - 2;
1452 while (start >= 0 && count > 0) {
1453 switch (parameterizedTypeSignature[--start]) {
1454 case C_GENERIC_START:
1462 if (start < 0) // invalid number of generic start/end
1463 throw new IllegalArgumentException();
1464 ArrayList args = new ArrayList();
1467 if (p >= parameterizedTypeSignature.length) {
1468 throw new IllegalArgumentException();
1470 char c = parameterizedTypeSignature[p];
1471 if (c == C_GENERIC_END) {
1472 int size = args.size();
1473 char[][] result = new char[size][];
1474 args.toArray(result);
1477 int e = scanTypeArgumentSignature(parameterizedTypeSignature, p);
1478 args.add(CharOperation.subarray(parameterizedTypeSignature, p, e+1));
1484 * Extracts the type argument signatures from the given type signature.
1485 * Returns an empty array if the type signature is not a parameterized type signature.
1487 * @param parameterizedTypeSignature the parameterized type signature
1488 * @return the signatures of the type arguments
1489 * @exception IllegalArgumentException if the signature is syntactically incorrect
1493 public static String[] getTypeArguments(String parameterizedTypeSignature) throws IllegalArgumentException {
1494 char[][] args = getTypeArguments(parameterizedTypeSignature.toCharArray());
1495 return CharOperation.toStrings(args);
1499 * Extracts the type erasure signature from the given parameterized type signature.
1500 * Returns the given type signature if it is not parameterized.
1502 * @param parameterizedTypeSignature the parameterized type signature
1503 * @return the signature of the type erasure
1504 * @exception IllegalArgumentException if the signature is syntactically
1509 public static char[] getTypeErasure(char[] parameterizedTypeSignature) throws IllegalArgumentException {
1510 int end = CharOperation.indexOf(C_GENERIC_START, parameterizedTypeSignature);
1511 if (end == -1) return parameterizedTypeSignature;
1512 int length = parameterizedTypeSignature.length;
1513 char[] result = new char[length];
1517 for (int idx=end; idx<length; idx++) {
1518 switch (parameterizedTypeSignature[idx]) {
1519 case C_GENERIC_START:
1521 int size = idx-start;
1522 System.arraycopy(parameterizedTypeSignature, start, result, pos, size);
1530 if (deep < 0) throw new IllegalArgumentException();
1531 if (deep == 0) start = idx+1;
1535 if (deep > 0) throw new IllegalArgumentException();
1536 int size = pos+length-start;
1537 char[] resized = new char[size];
1538 System.arraycopy(result, 0, resized, 0, pos);
1539 System.arraycopy(parameterizedTypeSignature, start, resized, pos, length-start);
1544 * Extracts the type erasure signature from the given parameterized type signature.
1545 * Returns the given type signature if it is not parameterized.
1547 * @param parameterizedTypeSignature the parameterized type signature
1548 * @return the signature of the type erasure
1549 * @exception IllegalArgumentException if the signature is syntactically
1554 public static String getTypeErasure(String parameterizedTypeSignature) throws IllegalArgumentException {
1555 return new String(getTypeErasure(parameterizedTypeSignature.toCharArray()));
1559 * Extracts the type parameter signatures from the given method or type signature.
1560 * The method or type signature is expected to be dot-based.
1562 * @param methodOrTypeSignature the method or type signature
1563 * @return the list of type parameter signatures
1564 * @exception IllegalArgumentException if the signature is syntactically
1569 public static char[][] getTypeParameters(char[] methodOrTypeSignature) throws IllegalArgumentException {
1571 int length = methodOrTypeSignature.length;
1572 if (length == 0) return CharOperation.NO_CHAR_CHAR;
1573 if (methodOrTypeSignature[0] != C_GENERIC_START) return CharOperation.NO_CHAR_CHAR;
1575 ArrayList paramList = new ArrayList(1);
1576 int paramStart = 1, i = 1; // start after leading '<'
1577 while (i < length) {
1578 if (methodOrTypeSignature[i] == C_GENERIC_END) {
1579 int size = paramList.size();
1580 if (size == 0) throw new IllegalArgumentException();
1582 paramList.toArray(result = new char[size][]);
1585 i = CharOperation.indexOf(C_COLON, methodOrTypeSignature, i);
1586 if (i < 0 || i >= length) throw new IllegalArgumentException();
1587 // iterate over bounds
1588 nextBound: while (methodOrTypeSignature[i] == ':') {
1590 if (methodOrTypeSignature[i] == ':') {
1591 continue nextBound; // empty bound
1593 i = scanTypeSignature(methodOrTypeSignature, i);
1594 i++; // position at start of next param if any
1596 paramList.add(CharOperation.subarray(methodOrTypeSignature, paramStart, i));
1597 paramStart = i; // next param start from here
1599 } catch (ArrayIndexOutOfBoundsException e) {
1600 // invalid signature, fall through
1602 throw new IllegalArgumentException();
1605 * Extracts the type parameter signatures from the given method or type signature.
1606 * The method or type signature is expected to be dot-based.
1608 * @param methodOrTypeSignature the method or type signature
1609 * @return the list of type parameter signatures
1610 * @exception IllegalArgumentException if the signature is syntactically
1615 public static String[] getTypeParameters(String methodOrTypeSignature) throws IllegalArgumentException {
1616 char[][] params = getTypeParameters(methodOrTypeSignature.toCharArray());
1617 return CharOperation.toStrings(params);
1621 * Extracts the type variable name from the given formal type parameter
1622 * signature. The signature is expected to be dot-based.
1624 * @param formalTypeParameterSignature the formal type parameter signature
1625 * @return the name of the type variable
1626 * @exception IllegalArgumentException if the signature is syntactically
1630 public static String getTypeVariable(String formalTypeParameterSignature) throws IllegalArgumentException {
1631 return new String(getTypeVariable(formalTypeParameterSignature.toCharArray()));
1635 * Extracts the type variable name from the given formal type parameter
1636 * signature. The signature is expected to be dot-based.
1638 * @param formalTypeParameterSignature the formal type parameter signature
1639 * @return the name of the type variable
1640 * @exception IllegalArgumentException if the signature is syntactically
1644 public static char[] getTypeVariable(char[] formalTypeParameterSignature) throws IllegalArgumentException {
1645 int p = CharOperation.indexOf(C_COLON, formalTypeParameterSignature);
1647 // no ":" means can't be a formal type parameter signature
1648 throw new IllegalArgumentException();
1650 return CharOperation.subarray(formalTypeParameterSignature, 0, p);
1654 * Extracts the class and interface bounds from the given formal type
1655 * parameter signature. The class bound, if present, is listed before
1656 * the interface bounds. The signature is expected to be dot-based.
1658 * @param formalTypeParameterSignature the formal type parameter signature
1659 * @return the (possibly empty) list of type signatures for the bounds
1660 * @exception IllegalArgumentException if the signature is syntactically
1664 public static char[][] getTypeParameterBounds(char[] formalTypeParameterSignature) throws IllegalArgumentException {
1665 int p1 = CharOperation.indexOf(C_COLON, formalTypeParameterSignature);
1667 // no ":" means can't be a formal type parameter signature
1668 throw new IllegalArgumentException();
1670 if (p1 == formalTypeParameterSignature.length - 1) {
1671 // no class or interface bounds
1672 return CharOperation.NO_CHAR_CHAR;
1674 int p2 = CharOperation.indexOf(C_COLON, formalTypeParameterSignature, p1 + 1);
1677 // no interface bounds
1678 classBound = CharOperation.subarray(formalTypeParameterSignature, p1 + 1, formalTypeParameterSignature.length);
1679 return new char[][] {classBound};
1682 // no class bound, but 1 or more interface bounds
1685 classBound = CharOperation.subarray(formalTypeParameterSignature, p1 + 1, p2);
1687 char[][] interfaceBounds = CharOperation.splitOn(C_COLON, formalTypeParameterSignature, p2 + 1, formalTypeParameterSignature.length);
1688 if (classBound == null) {
1689 return interfaceBounds;
1691 int resultLength = interfaceBounds.length + 1;
1692 char[][] result = new char[resultLength][];
1693 result[0] = classBound;
1694 System.arraycopy(interfaceBounds, 0, result, 1, interfaceBounds.length);
1699 * Extracts the class and interface bounds from the given formal type
1700 * parameter signature. The class bound, if present, is listed before
1701 * the interface bounds. The signature is expected to be dot-based.
1703 * @param formalTypeParameterSignature the formal type parameter signature
1704 * @return the (possibly empty) list of type signatures for the bounds
1705 * @exception IllegalArgumentException if the signature is syntactically
1709 public static String[] getTypeParameterBounds(String formalTypeParameterSignature) throws IllegalArgumentException {
1710 char[][] bounds = getTypeParameterBounds(formalTypeParameterSignature.toCharArray());
1711 return CharOperation.toStrings(bounds);
1715 * Returns a char array containing all but the last segment of the given
1716 * dot-separated qualified name. Returns the empty char array if it is not qualified.
1721 * getQualifier({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g'}
1722 * getQualifier({'O', 'u', 't', 'e', 'r', '.', 'I', 'n', 'n', 'e', 'r'}) -> {'O', 'u', 't', 'e', 'r'}
1723 * getQualifier({'j', 'a', 'v', 'a', '.', 'u', 't', 'i', 'l', '.', 'L', 'i', 's', 't', '<', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', '>'}) -> {'j', 'a', 'v', 'a', '.', 'u', 't', 'i', 'l'}
1728 * @param name the name
1729 * @return the qualifier prefix, or the empty char array if the name contains no
1731 * @exception NullPointerException if name is null
1734 public static char[] getQualifier(char[] name) {
1735 int firstGenericStart = CharOperation.indexOf(C_GENERIC_START, name);
1736 int lastDot = CharOperation.lastIndexOf(C_DOT, name, 0, firstGenericStart == -1 ? name.length-1 : firstGenericStart);
1737 if (lastDot == -1) {
1738 return CharOperation.NO_CHAR;
1740 return CharOperation.subarray(name, 0, lastDot);
1743 * Returns a string containing all but the last segment of the given
1744 * dot-separated qualified name. Returns the empty string if it is not qualified.
1749 * getQualifier("java.lang.Object") -> "java.lang"
1750 * getQualifier("Outer.Inner") -> "Outer"
1751 * getQualifier("java.util.List<java.lang.String>") -> "java.util"
1756 * @param name the name
1757 * @return the qualifier prefix, or the empty string if the name contains no
1759 * @exception NullPointerException if name is null
1761 public static String getQualifier(String name) {
1762 char[] qualifier = getQualifier(name.toCharArray());
1763 if (qualifier.length == 0) return EMPTY;
1764 return new String(qualifier);
1767 * Extracts the return type from the given method signature. The method signature is
1768 * expected to be dot-based.
1770 * @param methodSignature the method signature
1771 * @return the type signature of the return type
1772 * @exception IllegalArgumentException if the signature is syntactically
1777 public static char[] getReturnType(char[] methodSignature) throws IllegalArgumentException {
1778 // skip type parameters
1779 int paren = CharOperation.lastIndexOf(C_PARAM_END, methodSignature);
1781 throw new IllegalArgumentException();
1783 // there could be thrown exceptions behind, thus scan one type exactly
1784 int last = scanTypeSignature(methodSignature, paren+1);
1785 return CharOperation.subarray(methodSignature, paren + 1, last+1);
1788 * Extracts the return type from the given method signature. The method signature is
1789 * expected to be dot-based.
1791 * @param methodSignature the method signature
1792 * @return the type signature of the return type
1793 * @exception IllegalArgumentException if the signature is syntactically
1796 public static String getReturnType(String methodSignature) throws IllegalArgumentException {
1797 return new String(getReturnType(methodSignature.toCharArray()));
1800 * Returns package fragment of a type signature. The package fragment separator must be '.'
1801 * and the type fragment separator must be '$'.
1806 * getSignatureQualifier({'L', 'j', 'a', 'v', 'a', '.', 'u', 't', 'i', 'l', '.', 'M', 'a', 'p', '$', 'E', 'n', 't', 'r', 'y', ';'}) -> {'j', 'a', 'v', 'a', '.', 'u', 't', 'i', 'l'}
1811 * @param typeSignature the type signature
1812 * @return the package fragment (separators are '.')
1815 public static char[] getSignatureQualifier(char[] typeSignature) {
1816 if(typeSignature == null) return CharOperation.NO_CHAR;
1818 char[] qualifiedType = Signature.toCharArray(typeSignature);
1821 indexFound: for(int i = 0; i < typeSignature.length; i++) {
1822 switch(typeSignature[i]) {
1826 case C_GENERIC_START:
1834 for(int i = 0; i < qualifiedType.length; i++) {
1835 if(qualifiedType[i] == '.') {
1839 return CharOperation.subarray(qualifiedType, 0, i);
1843 return CharOperation.NO_CHAR;
1846 * Returns package fragment of a type signature. The package fragment separator must be '.'
1847 * and the type fragment separator must be '$'.
1852 * getSignatureQualifier("Ljava.util.Map$Entry") -> "java.util"
1857 * @param typeSignature the type signature
1858 * @return the package fragment (separators are '.')
1861 public static String getSignatureQualifier(String typeSignature) {
1862 return new String(getSignatureQualifier(typeSignature == null ? null : typeSignature.toCharArray()));
1865 * Returns type fragment of a type signature. The package fragment separator must be '.'
1866 * and the type fragment separator must be '$'.
1871 * getSignatureSimpleName({'L', 'j', 'a', 'v', 'a', '.', 'u', 't', 'i', 'l', '.', 'M', 'a', 'p', '$', 'E', 'n', 't', 'r', 'y', ';'}) -> {'M', 'a', 'p', '.', 'E', 'n', 't', 'r', 'y'}
1876 * @param typeSignature the type signature
1877 * @return the type fragment (separators are '.')
1880 public static char[] getSignatureSimpleName(char[] typeSignature) {
1881 if(typeSignature == null) return CharOperation.NO_CHAR;
1883 char[] qualifiedType = Signature.toCharArray(typeSignature);
1886 indexFound: for(int i = 0; i < typeSignature.length; i++) {
1887 switch(typeSignature[i]) {
1891 case C_GENERIC_START:
1899 for(int i = 0; i < qualifiedType.length; i++) {
1900 if(qualifiedType[i] == '.') {
1904 return CharOperation.subarray(qualifiedType, i + 1, qualifiedType.length);
1908 return qualifiedType;
1911 * Returns type fragment of a type signature. The package fragment separator must be '.'
1912 * and the type fragment separator must be '$'.
1917 * getSignatureSimpleName("Ljava.util.Map$Entry") -> "Map.Entry"
1922 * @param typeSignature the type signature
1923 * @return the type fragment (separators are '.')
1926 public static String getSignatureSimpleName(String typeSignature) {
1927 return new String(getSignatureSimpleName(typeSignature == null ? null : typeSignature.toCharArray()));
1931 * Returns the last segment of the given dot-separated qualified name.
1932 * Returns the given name if it is not qualified.
1937 * getSimpleName({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'O', 'b', 'j', 'e', 'c', 't'}
1942 * @param name the name
1943 * @return the last segment of the qualified name
1944 * @exception NullPointerException if name is null
1947 public static char[] getSimpleName(char[] name) {
1949 int lastDot = -1, lastGenericStart = -1, lastGenericEnd = -1;
1951 int length = name.length;
1952 lastDotLookup: for (int i = length -1; i >= 0; i--) {
1957 break lastDotLookup;
1962 if (depth == 0) lastGenericStart = i;
1965 if (depth == 0) lastGenericEnd = i;
1970 if (lastGenericStart < 0) {
1974 return CharOperation.subarray(name, lastDot + 1, length);
1976 StringBuffer buffer = new StringBuffer(10);
1977 int nameStart = lastDot < 0 ? 0 : lastDot+1;
1978 buffer.append(name, nameStart, lastGenericStart - nameStart);
1979 appendArgumentSimpleNames(name, lastGenericStart, lastGenericEnd, buffer);
1980 buffer.append(name, lastGenericEnd+1, length-lastGenericEnd-1); // copy trailing portion, may contain dimensions
1981 char[] result = new char[length = buffer.length()];
1982 buffer.getChars(0, length, result, 0);
1986 * Returns the last segment of the given dot-separated qualified name.
1987 * Returns the given name if it is not qualified.
1992 * getSimpleName("java.lang.Object") -> "Object"
1995 * getSimpleName("java.util.Map<java.lang.String, java.lang.Object>") -> "Map<String,Object>"
2000 * @param name the name
2001 * @return the last segment of the qualified name
2002 * @exception NullPointerException if name is null
2004 public static String getSimpleName(String name) {
2005 int lastDot = -1, lastGenericStart = -1, lastGenericEnd = -1;
2007 int length = name.length();
2008 lastDotLookup: for (int i = length -1; i >= 0; i--) {
2009 switch (name.charAt(i)) {
2013 break lastDotLookup;
2018 if (depth == 0) lastGenericStart = i;
2021 if (depth == 0) lastGenericEnd = i;
2026 if (lastGenericStart < 0) {
2030 return name.substring(lastDot + 1, length);
2032 StringBuffer buffer = new StringBuffer(10);
2033 char[] nameChars = name.toCharArray();
2034 int nameStart = lastDot < 0 ? 0 : lastDot+1;
2035 buffer.append(nameChars, nameStart, lastGenericStart - nameStart);
2036 appendArgumentSimpleNames(nameChars, lastGenericStart, lastGenericEnd, buffer);
2037 buffer.append(nameChars, lastGenericEnd+1, length-lastGenericEnd-1); // copy trailing portion, may contain dimensions
2038 return buffer.toString();
2041 private static void appendSimpleName(char[] name, int start, int end, StringBuffer buffer) {
2042 int lastDot = -1, lastGenericStart = -1, lastGenericEnd = -1;
2044 if (name[start] == '?') { // wildcard
2045 buffer.append("? "); //$NON-NLS-1$
2046 int index = consumeWhitespace(name, start+1, end+1);
2047 switch (name[index]) {
2049 int checkPos = checkName(EXTENDS, name, index, end);
2051 buffer.append(EXTENDS).append(' ');
2052 index = consumeWhitespace(name, checkPos, end+1);
2056 checkPos = checkName(SUPER, name, index, end+1);
2058 buffer.append(SUPER).append(' ');
2059 index = consumeWhitespace(name, checkPos, end+1);
2063 start = index; // leading segment got processed
2065 lastDotLookup: for (int i = end; i >= start; i--) {
2070 break lastDotLookup;
2075 if (depth == 0) lastGenericStart = i;
2078 if (depth == 0) lastGenericEnd = i;
2083 int nameStart = lastDot < 0 ? start : lastDot+1;
2084 int nameEnd = lastGenericStart < 0 ? end+1 : lastGenericStart;
2085 buffer.append(name, nameStart, nameEnd - nameStart);
2086 if (lastGenericStart >= 0) {
2087 appendArgumentSimpleNames(name, lastGenericStart, lastGenericEnd, buffer);
2088 buffer.append(name, lastGenericEnd+1, end - lastGenericEnd); // copy trailing portion, may contain dimensions
2091 // <x.y.z, a.b<c>.d<e.f>> --> <z,d<f>>
2092 private static void appendArgumentSimpleNames(char[] name, int start, int end, StringBuffer buffer) {
2095 int argumentStart = -1;
2096 int argumentCount = 0;
2097 for (int i = start; i <= end; i++) {
2102 argumentStart = i+1;
2107 if (argumentCount > 0) buffer.append(',');
2108 appendSimpleName(name, argumentStart, i-1, buffer);
2115 if (argumentCount > 0) buffer.append(',');
2116 appendSimpleName(name, argumentStart, i-1, buffer);
2118 argumentStart = i+1;
2126 * Returns all segments of the given dot-separated qualified name.
2127 * Returns an array with only the given name if it is not qualified.
2128 * Returns an empty array if the name is empty.
2133 * 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'}}
2134 * getSimpleNames({'O', 'b', 'j', 'e', 'c', 't'}) -> {{'O', 'b', 'j', 'e', 'c', 't'}}
2135 * getSimpleNames({}) -> {}
2136 * getSimpleNames({'j', 'a', 'v', 'a', '.', 'u', 't', 'i', 'l', '.', 'L', 'i', 's', 't', '<', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', '>'}) -> {{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'L', 'i', 's', 't', '<', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g'}}
2140 * @param name the name
2141 * @return the list of simple names, possibly empty
2142 * @exception NullPointerException if name is null
2145 public static char[][] getSimpleNames(char[] name) {
2146 int length = name == null ? 0 : name.length;
2148 return CharOperation.NO_CHAR_CHAR;
2151 countingWords: for (int i = 0; i < length; i++)
2156 case C_GENERIC_START:
2157 break countingWords;
2159 char[][] split = new char[wordCount][];
2160 int last = 0, currentWord = 0;
2161 for (int i = 0; i < length; i++) {
2162 if (name[i] == C_GENERIC_START) break;
2163 if (name[i] == C_DOT) {
2164 split[currentWord] = new char[i - last];
2168 split[currentWord++],
2174 split[currentWord] = new char[length - last];
2175 System.arraycopy(name, last, split[currentWord], 0, length - last);
2179 * Returns all segments of the given dot-separated qualified name.
2180 * Returns an array with only the given name if it is not qualified.
2181 * Returns an empty array if the name is empty.
2186 * getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
2187 * getSimpleNames("Object") -> {"Object"}
2188 * getSimpleNames("") -> {}
2189 * getSimpleNames("java.util.List<java.lang.String>") -> {"java", "lang", "List<java.lang.String"}
2193 * @param name the name
2194 * @return the list of simple names, possibly empty
2195 * @exception NullPointerException if name is null
2197 public static String[] getSimpleNames(String name) {
2198 return CharOperation.toStrings(getSimpleNames(name.toCharArray()));
2201 * Converts the given method signature to a readable form. The method signature is expected to
2207 * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
2212 * @param methodSignature the method signature to convert
2213 * @param methodName the name of the method to insert in the result, or
2214 * <code>null</code> if no method name is to be included
2215 * @param parameterNames the parameter names to insert in the result, or
2216 * <code>null</code> if no parameter names are to be included; if supplied,
2217 * the number of parameter names must match that of the method signature
2218 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2219 * qualified, and <code>false</code> to use only simple names
2220 * @param includeReturnType <code>true</code> if the return type is to be
2222 * @return the char array representation of the method signature
2226 public static char[] toCharArray(char[] methodSignature, char[] methodName, char[][] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
2227 return toCharArray(methodSignature, methodName, parameterNames, fullyQualifyTypeNames, includeReturnType, false);
2230 * Converts the given method signature to a readable form. The method signature is expected to
2236 * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
2241 * @param methodSignature the method signature to convert
2242 * @param methodName the name of the method to insert in the result, or
2243 * <code>null</code> if no method name is to be included
2244 * @param parameterNames the parameter names to insert in the result, or
2245 * <code>null</code> if no parameter names are to be included; if supplied,
2246 * the number of parameter names must match that of the method signature
2247 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2248 * qualified, and <code>false</code> to use only simple names
2249 * @param includeReturnType <code>true</code> if the return type is to be
2251 * @param isVargArgs <code>true</code> if the last argument should be displayed as a
2252 * variable argument, <code>false</code> otherwise.
2253 * @return the char array representation of the method signature
2257 public static char[] toCharArray(char[] methodSignature, char[] methodName, char[][] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType, boolean isVargArgs) {
2258 int firstParen = CharOperation.indexOf(C_PARAM_START, methodSignature);
2259 if (firstParen == -1) {
2260 throw new IllegalArgumentException();
2263 StringBuffer buffer = new StringBuffer(methodSignature.length + 10);
2266 if (includeReturnType) {
2267 char[] rts = getReturnType(methodSignature);
2268 appendTypeSignature(rts, 0 , fullyQualifyTypeNames, buffer);
2273 if (methodName != null) {
2274 buffer.append(methodName);
2279 char[][] pts = getParameterTypes(methodSignature);
2280 for (int i = 0, max = pts.length; i < max; i++) {
2282 appendTypeSignature(pts[i], 0 , fullyQualifyTypeNames, buffer, isVargArgs);
2284 appendTypeSignature(pts[i], 0 , fullyQualifyTypeNames, buffer);
2286 if (parameterNames != null) {
2288 buffer.append(parameterNames[i]);
2290 if (i != pts.length - 1) {
2296 char[] result = new char[buffer.length()];
2297 buffer.getChars(0, buffer.length(), result, 0);
2301 * Converts the given type signature to a readable string. The signature is expected to
2308 * 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', '[', ']'}
2309 * toString({'I'}) -> {'i', 'n', 't'}
2310 * toString({'+', 'L', 'O', 'b', 'j', 'e', 'c', 't', ';'}) -> {'?', ' ', 'e', 'x', 't', 'e', 'n', 'd', 's', ' ', 'O', 'b', 'j', 'e', 'c', 't'}
2315 * Note: This method assumes that a type signature containing a <code>'$'</code>
2316 * is an inner type signature. While this is correct in most cases, someone could
2317 * define a non-inner type name containing a <code>'$'</code>. Handling this
2318 * correctly in all cases would have required resolving the signature, which
2319 * generally not feasible.
2322 * @param signature the type signature
2323 * @return the string representation of the type
2324 * @exception IllegalArgumentException if the signature is not syntactically
2329 public static char[] toCharArray(char[] signature) throws IllegalArgumentException {
2330 int sigLength = signature.length;
2331 if (sigLength == 0 || signature[0] == C_PARAM_START || signature[0] == C_GENERIC_START) {
2332 return toCharArray(signature, CharOperation.NO_CHAR, null, true, true);
2335 StringBuffer buffer = new StringBuffer(signature.length + 10);
2336 appendTypeSignature(signature, 0, true, buffer);
2337 char[] result = new char[buffer.length()];
2338 buffer.getChars(0, buffer.length(), result, 0);
2343 * Scans the given string for a type signature starting at the given
2344 * index and appends it to the given buffer, and returns the index of the last
2347 * @param string the signature string
2348 * @param start the 0-based character index of the first character
2349 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2350 * qualified, and <code>false</code> to use only simple names
2351 * @param buffer the string buffer to append to
2352 * @return the 0-based character index of the last character
2353 * @exception IllegalArgumentException if this is not a type signature
2354 * @see #scanTypeSignature(char[], int)
2356 private static int appendTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
2357 return appendTypeSignature(string, start, fullyQualifyTypeNames, buffer, false);
2360 * Scans the given string for a type signature starting at the given
2361 * index and appends it to the given buffer, and returns the index of the last
2364 * @param string the signature string
2365 * @param start the 0-based character index of the first character
2366 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2367 * qualified, and <code>false</code> to use only simple names
2368 * @param buffer the string buffer to append to
2369 * @param isVarArgs <code>true</code> if the type must be displayed as a
2370 * variable argument, <code>false</code> otherwise. In this case, the type must be an array type
2371 * @return the 0-based character index of the last character
2372 * @exception IllegalArgumentException if this is not a type signature, or if isVarArgs is <code>true</code>,
2373 * and the type is not an array type signature.
2374 * @see #scanTypeSignature(char[], int)
2376 private static int appendTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer, boolean isVarArgs) {
2377 // need a minimum 1 char
2378 if (start >= string.length) {
2379 throw new IllegalArgumentException();
2381 char c = string[start];
2385 return appendArrayTypeSignature(string, start, fullyQualifyTypeNames, buffer, true);
2388 case C_TYPE_VARIABLE :
2402 throw new IllegalArgumentException(); // a var args is an array type
2407 return appendArrayTypeSignature(string, start, fullyQualifyTypeNames, buffer);
2410 return appendClassTypeSignature(string, start, fullyQualifyTypeNames, buffer);
2411 case C_TYPE_VARIABLE :
2412 int e = scanTypeVariableSignature(string, start);
2413 buffer.append(CharOperation.subarray(string, start + 1, e));
2416 buffer.append(BOOLEAN);
2419 buffer.append(BYTE);
2422 buffer.append(CHAR);
2425 buffer.append(DOUBLE);
2428 buffer.append(FLOAT);
2434 buffer.append(LONG);
2437 buffer.append(SHORT);
2440 buffer.append(VOID);
2445 return appendTypeArgumentSignature(string, start, fullyQualifyTypeNames, buffer);
2447 throw new IllegalArgumentException();
2452 * Scans the given string for an array type signature starting at the given
2453 * index and appends it to the given buffer, and returns the index of the last
2456 * @param string the signature string
2457 * @param start the 0-based character index of the first character
2458 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2459 * qualified, and <code>false</code> to use only simple names
2460 * @return the 0-based character index of the last character
2461 * @exception IllegalArgumentException if this is not an array type signature
2462 * @see #scanArrayTypeSignature(char[], int)
2464 private static int appendArrayTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
2465 return appendArrayTypeSignature(string, start, fullyQualifyTypeNames, buffer, false);
2468 * Scans the given string for an array type signature starting at the given
2469 * index and appends it to the given buffer, and returns the index of the last
2472 * @param string the signature string
2473 * @param start the 0-based character index of the first character
2474 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2475 * qualified, and <code>false</code> to use only simple names
2476 * @param isVarArgs <code>true</code> if the array type must be displayed as a
2477 * variable argument, <code>false</code> otherwise
2478 * @return the 0-based character index of the last character
2479 * @exception IllegalArgumentException if this is not an array type signature
2480 * @see #scanArrayTypeSignature(char[], int)
2482 private static int appendArrayTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer, boolean isVarArgs) {
2483 // need a minimum 2 char
2484 if (start >= string.length - 1) {
2485 throw new IllegalArgumentException();
2487 char c = string[start];
2488 if (c != C_ARRAY) { //$NON-NLS-1$
2489 throw new IllegalArgumentException();
2491 int e = appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
2493 buffer.append('.').append('.').append('.');
2495 buffer.append('[').append(']');
2500 * Scans the given string for a class type signature starting at the given
2501 * index and appends it to the given buffer, and returns the index of the last
2504 * @param string the signature string
2505 * @param start the 0-based character index of the first character
2506 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2507 * qualified, and <code>false</code> to use only simple names
2508 * @param buffer the string buffer to append to
2509 * @return the 0-based character index of the last character
2510 * @exception IllegalArgumentException if this is not a class type signature
2511 * @see #scanClassTypeSignature(char[], int)
2513 private static int appendClassTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
2514 // need a minimum 3 chars "Lx;"
2515 if (start >= string.length - 2) {
2516 throw new IllegalArgumentException();
2518 // must start in "L" or "Q"
2519 char c = string[start];
2520 if (c != C_RESOLVED && c != C_UNRESOLVED) {
2521 throw new IllegalArgumentException();
2523 boolean resolved = (c == C_RESOLVED);
2524 boolean removePackageQualifiers = !fullyQualifyTypeNames;
2526 // keep everything in an unresolved name
2527 removePackageQualifiers = false;
2530 int checkpoint = buffer.length();
2532 if (p >= string.length) {
2533 throw new IllegalArgumentException();
2540 case C_GENERIC_START :
2541 int e = appendTypeArgumentSignatures(string, p, fullyQualifyTypeNames, buffer);
2542 // once we hit type arguments there are no more package prefixes
2543 removePackageQualifiers = false;
2547 if (removePackageQualifiers) {
2548 // erase package prefix
2549 buffer.setLength(checkpoint);
2555 if (removePackageQualifiers) {
2556 // erase package prefix
2557 buffer.setLength(checkpoint);
2564 // once we hit "$" there are no more package prefixes
2565 removePackageQualifiers = false;
2567 * Convert '$' in resolved type signatures into '.'.
2568 * NOTE: This assumes that the type signature is an inner type
2569 * signature. This is true in most cases, but someone can define a
2570 * non-inner type name containing a '$'.
2583 * Scans the given string for a list of type arguments signature starting at the
2584 * given index and appends it to the given buffer, and returns the index of the
2587 * @param string the signature string
2588 * @param start the 0-based character index of the first character
2589 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2590 * qualified, and <code>false</code> to use only simple names
2591 * @param buffer the string buffer to append to
2592 * @return the 0-based character index of the last character
2593 * @exception IllegalArgumentException if this is not a list of type argument
2595 * @see #scanTypeArgumentSignatures(char[], int)
2597 private static int appendTypeArgumentSignatures(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
2598 // need a minimum 2 char "<>"
2599 if (start >= string.length - 1) {
2600 throw new IllegalArgumentException();
2602 char c = string[start];
2603 if (c != C_GENERIC_START) {
2604 throw new IllegalArgumentException();
2610 if (p >= string.length) {
2611 throw new IllegalArgumentException();
2614 if (c == C_GENERIC_END) {
2621 int e = appendTypeArgumentSignature(string, p, fullyQualifyTypeNames, buffer);
2628 * Scans the given string for a type argument signature starting at the given
2629 * index and appends it to the given buffer, and returns the index of the last
2632 * @param string the signature string
2633 * @param start the 0-based character index of the first character
2634 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2635 * qualified, and <code>false</code> to use only simple names
2636 * @param buffer the string buffer to append to
2637 * @return the 0-based character index of the last character
2638 * @exception IllegalArgumentException if this is not a type argument signature
2639 * @see #scanTypeArgumentSignature(char[], int)
2641 private static int appendTypeArgumentSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer) {
2642 // need a minimum 1 char
2643 if (start >= string.length) {
2644 throw new IllegalArgumentException();
2646 char c = string[start];
2652 buffer.append("? extends "); //$NON-NLS-1$
2653 return appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
2655 buffer.append("? super "); //$NON-NLS-1$
2656 return appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
2658 return appendTypeSignature(string, start, fullyQualifyTypeNames, buffer);
2663 * Converts the given array of qualified name segments to a qualified name.
2668 * 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'}
2669 * toQualifiedName({{'O', 'b', 'j', 'e', 'c', 't'}}) -> {'O', 'b', 'j', 'e', 'c', 't'}
2670 * toQualifiedName({{}}) -> {}
2675 * @param segments the list of name segments, possibly empty
2676 * @return the dot-separated qualified name, or the empty string
2680 public static char[] toQualifiedName(char[][] segments) {
2681 int length = segments.length;
2682 if (length == 0) return CharOperation.NO_CHAR;
2683 if (length == 1) return segments[0];
2685 int resultLength = 0;
2686 for (int i = 0; i < length; i++) {
2687 resultLength += segments[i].length+1;
2690 char[] result = new char[resultLength];
2692 for (int i = 0; i < length; i++) {
2693 char[] segment = segments[i];
2694 int segmentLength = segment.length;
2695 System.arraycopy(segment, 0, result, index, segmentLength);
2696 index += segmentLength;
2697 if (i != length-1) {
2698 result[index++] = C_DOT;
2704 * Converts the given array of qualified name segments to a qualified name.
2709 * toQualifiedName(new String[] {"java", "lang", "Object"}) -> "java.lang.Object"
2710 * toQualifiedName(new String[] {"Object"}) -> "Object"
2711 * toQualifiedName(new String[0]) -> ""
2716 * @param segments the list of name segments, possibly empty
2717 * @return the dot-separated qualified name, or the empty string
2719 public static String toQualifiedName(String[] segments) {
2720 int length = segments.length;
2721 char[][] charArrays = new char[length][];
2722 for (int i = 0; i < length; i++) {
2723 charArrays[i] = segments[i].toCharArray();
2725 return new String(toQualifiedName(charArrays));
2728 * Converts the given type signature to a readable string. The signature is expected to
2735 * toString("[Ljava.lang.String;") -> "java.lang.String[]"
2736 * toString("I") -> "int"
2737 * toString("+QObject;") -> "? extends Object"
2742 * Note: This method assumes that a type signature containing a <code>'$'</code>
2743 * is an inner type signature. While this is correct in most cases, someone could
2744 * define a non-inner type name containing a <code>'$'</code>. Handling this
2745 * correctly in all cases would have required resolving the signature, which
2746 * generally not feasible.
2749 * @param signature the type signature
2750 * @return the string representation of the type
2751 * @exception IllegalArgumentException if the signature is not syntactically
2754 public static String toString(String signature) throws IllegalArgumentException {
2755 return new String(toCharArray(signature.toCharArray()));
2758 * Converts the given method signature to a readable string. The method signature is expected to
2761 * @param methodSignature the method signature to convert
2762 * @param methodName the name of the method to insert in the result, or
2763 * <code>null</code> if no method name is to be included
2764 * @param parameterNames the parameter names to insert in the result, or
2765 * <code>null</code> if no parameter names are to be included; if supplied,
2766 * the number of parameter names must match that of the method signature
2767 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2768 * qualified, and <code>false</code> to use only simple names
2769 * @param includeReturnType <code>true</code> if the return type is to be
2771 * @see #toCharArray(char[], char[], char[][], boolean, boolean)
2772 * @return the string representation of the method signature
2774 public static String toString(String methodSignature, String methodName, String[] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
2775 return toString(methodSignature, methodName, parameterNames, fullyQualifyTypeNames, includeReturnType, false);
2778 * Converts the given method signature to a readable string. The method signature is expected to
2781 * @param methodSignature the method signature to convert
2782 * @param methodName the name of the method to insert in the result, or
2783 * <code>null</code> if no method name is to be included
2784 * @param parameterNames the parameter names to insert in the result, or
2785 * <code>null</code> if no parameter names are to be included; if supplied,
2786 * the number of parameter names must match that of the method signature
2787 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
2788 * qualified, and <code>false</code> to use only simple names
2789 * @param includeReturnType <code>true</code> if the return type is to be
2791 * @param isVarArgs <code>true</code> if the last argument should be displayed as a
2792 * variable argument, <code>false</code> otherwise
2793 * @see #toCharArray(char[], char[], char[][], boolean, boolean)
2794 * @return the string representation of the method signature
2796 public static String toString(String methodSignature, String methodName, String[] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType, boolean isVarArgs) {
2798 if (parameterNames == null) {
2801 int paramLength = parameterNames.length;
2802 params = new char[paramLength][];
2803 for (int i = 0; i < paramLength; i++) {
2804 params[i] = parameterNames[i].toCharArray();
2807 return new String(toCharArray(methodSignature.toCharArray(), methodName == null ? null : methodName.toCharArray(), params, fullyQualifyTypeNames, includeReturnType, isVarArgs));