1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.core;
13 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
14 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
15 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
16 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
19 * Provides methods for encoding and decoding type and method signature strings.
21 * The syntax for a type signature is:
33 * | "L" + binaryTypeName + ";" // resolved named type (i.e., in compiled code)
34 * | "Q" + sourceTypeName + ";" // unresolved named type (i.e., in source code)
35 * | "[" + typeSignature // array of type denoted by typeSignature
41 * <li><code>"[[I"</code> denotes <code>int[][]</code></li>
42 * <li><code>"Ljava.lang.String;"</code> denotes <code>java.lang.String</code> in compiled code</li>
43 * <li><code>"QString"</code> denotes <code>String</code> in source code</li>
44 * <li><code>"Qjava.lang.String"</code> denotes <code>java.lang.String</code> in source code</li>
45 * <li><code>"[QString"</code> denotes <code>String[]</code> in source code</li>
49 * The syntax for a method signature is:
51 * methodSignature ::= "(" + paramTypeSignature* + ")" + returnTypeSignature
52 * paramTypeSignature ::= typeSignature
53 * returnTypeSignature ::= typeSignature
58 * <li><code>"()I"</code> denotes <code>int foo()</code></li>
59 * <li><code>"([Ljava.lang.String;)V"</code> denotes <code>void foo(java.lang.String[])</code> in compiled code</li>
60 * <li><code>"(QString;)QObject;"</code> denotes <code>Object foo(String)</code> in source code</li>
64 * This class provides static methods and constants only; it is not intended to be
65 * instantiated or subclassed by clients.
68 public final class Signature {
71 * Character constant indicating the primitive type boolean in a signature.
72 * Value is <code>'Z'</code>.
74 public static final char C_BOOLEAN = 'Z';
77 * Character constant indicating the primitive type byte in a signature.
78 * Value is <code>'B'</code>.
80 public static final char C_BYTE = 'B';
83 * Character constant indicating the primitive type char in a signature.
84 * Value is <code>'C'</code>.
86 public static final char C_CHAR = 'C';
89 * Character constant indicating the primitive type double in a signature.
90 * Value is <code>'D'</code>.
92 public static final char C_DOUBLE = 'D';
95 * Character constant indicating the primitive type float in a signature.
96 * Value is <code>'F'</code>.
98 public static final char C_FLOAT = 'F';
101 * Character constant indicating the primitive type int in a signature.
102 * Value is <code>'I'</code>.
104 public static final char C_INT = 'I';
107 * Character constant indicating the semicolon in a signature.
108 * Value is <code>';'</code>.
110 public static final char C_SEMICOLON = ';';
113 * Character constant indicating the primitive type long in a signature.
114 * Value is <code>'J'</code>.
116 public static final char C_LONG = 'J';
119 * Character constant indicating the primitive type short in a signature.
120 * Value is <code>'S'</code>.
122 public static final char C_SHORT = 'S';
125 * Character constant indicating result type void in a signature.
126 * Value is <code>'V'</code>.
128 public static final char C_VOID = 'V';
131 * Character constant indicating the dot in a signature.
132 * Value is <code>'.'</code>.
134 public static final char C_DOT = '.';
137 * Character constant indicating the dollar in a signature.
138 * Value is <code>'$'</code>.
140 public static final char C_DOLLAR = '$';
143 * Character constant indicating an array type in a signature.
144 * Value is <code>'['</code>.
146 public static final char C_ARRAY = '[';
149 * Character constant indicating the start of a resolved, named type in a
150 * signature. Value is <code>'L'</code>.
152 public static final char C_RESOLVED = 'L';
155 * Character constant indicating the start of an unresolved, named type in a
156 * signature. Value is <code>'Q'</code>.
158 public static final char C_UNRESOLVED = 'Q';
161 * Character constant indicating the end of a named type in a signature.
162 * Value is <code>';'</code>.
164 public static final char C_NAME_END = ';';
167 * Character constant indicating the start of a parameter type list in a
168 * signature. Value is <code>'('</code>.
170 public static final char C_PARAM_START = '(';
173 * Character constant indicating the end of a parameter type list in a
174 * signature. Value is <code>')'</code>.
176 public static final char C_PARAM_END = ')';
179 * String constant for the signature of the primitive type boolean.
180 * Value is <code>"Z"</code>.
182 public static final String SIG_BOOLEAN = "Z"; //$NON-NLS-1$
185 * String constant for the signature of the primitive type byte.
186 * Value is <code>"B"</code>.
188 public static final String SIG_BYTE = "B"; //$NON-NLS-1$
191 * String constant for the signature of the primitive type char.
192 * Value is <code>"C"</code>.
194 public static final String SIG_CHAR = "C"; //$NON-NLS-1$
197 * String constant for the signature of the primitive type double.
198 * Value is <code>"D"</code>.
200 public static final String SIG_DOUBLE = "D"; //$NON-NLS-1$
203 * String constant for the signature of the primitive type float.
204 * Value is <code>"F"</code>.
206 public static final String SIG_FLOAT = "F"; //$NON-NLS-1$
209 * String constant for the signature of the primitive type int.
210 * Value is <code>"I"</code>.
212 public static final String SIG_INT = "I"; //$NON-NLS-1$
215 * String constant for the signature of the primitive type long.
216 * Value is <code>"J"</code>.
218 public static final String SIG_LONG = "J"; //$NON-NLS-1$
221 * String constant for the signature of the primitive type short.
222 * Value is <code>"S"</code>.
224 public static final String SIG_SHORT = "S"; //$NON-NLS-1$
226 /** String constant for the signature of result type void.
227 * Value is <code>"V"</code>.
229 public static final String SIG_VOID = "V"; //$NON-NLS-1$
231 private static final char[] NO_CHAR = new char[0];
232 private static final char[][] NO_CHAR_CHAR = new char[0][];
233 private static final char[] BOOLEAN = {'b', 'o', 'o', 'l', 'e', 'a', 'n'};
234 private static final char[] BYTE = {'b', 'y', 't', 'e'};
235 private static final char[] CHAR = {'c', 'h', 'a', 'r'};
236 private static final char[] DOUBLE = {'d', 'o', 'u', 'b', 'l', 'e'};
237 private static final char[] FLOAT = {'f', 'l', 'o', 'a', 't'};
238 private static final char[] INT = {'i', 'n', 't'};
239 private static final char[] LONG = {'l', 'o', 'n', 'g'};
240 private static final char[] SHORT = {'s', 'h', 'o', 'r', 't'};
241 private static final char[] VOID = {'v', 'o', 'i', 'd'};
247 private Signature() {}
249 private static long copyType(char[] signature, int sigPos, char[] dest, int index, boolean fullyQualifyTypeNames) {
252 switch (signature[sigPos++]) {
257 int length = BOOLEAN.length;
258 System.arraycopy(BOOLEAN, 0, dest, index, length);
262 length = BYTE.length;
263 System.arraycopy(BYTE, 0, dest, index, length);
267 length = CHAR.length;
268 System.arraycopy(CHAR, 0, dest, index, length);
272 length = DOUBLE.length;
273 System.arraycopy(DOUBLE, 0, dest, index, length);
277 length = FLOAT.length;
278 System.arraycopy(FLOAT, 0, dest, index, length);
283 System.arraycopy(INT, 0, dest, index, length);
287 length = LONG.length;
288 System.arraycopy(LONG, 0, dest, index, length);
292 length = SHORT.length;
293 System.arraycopy(SHORT, 0, dest, index, length);
297 length = VOID.length;
298 System.arraycopy(VOID, 0, dest, index, length);
303 int end = CharOperation.indexOf(C_SEMICOLON, signature, sigPos);
304 if (end == -1) throw new IllegalArgumentException();
306 if (fullyQualifyTypeNames) {
309 start = CharOperation.lastIndexOf(C_DOT, signature, sigPos, end)+1;
310 if (start == 0) start = sigPos;
313 System.arraycopy(signature, start, dest, index, length);
319 while (arrayCount-- > 0) {
323 return (((long) index) << 32) + sigPos;
326 * Creates a new type signature with the given amount of array nesting added
327 * to the given type signature.
329 * @param typeSignature the type signature
330 * @param arrayCount the desired number of levels of array nesting
331 * @return the encoded array type signature
335 public static char[] createArraySignature(char[] typeSignature, int arrayCount) {
336 if (arrayCount == 0) return typeSignature;
337 int sigLength = typeSignature.length;
338 char[] result = new char[arrayCount + sigLength];
339 for (int i = 0; i < arrayCount; i++) {
342 System.arraycopy(typeSignature, 0, result, arrayCount, sigLength);
346 * Creates a new type signature with the given amount of array nesting added
347 * to the given type signature.
349 * @param typeSignature the type signature
350 * @param arrayCount the desired number of levels of array nesting
351 * @return the encoded array type signature
353 public static String createArraySignature(String typeSignature, int arrayCount) {
354 return new String(createArraySignature(typeSignature.toCharArray(), arrayCount));
357 * Creates a method signature from the given parameter and return type
358 * signatures. The encoded method signature is dot-based.
360 * @param parameterTypes the list of parameter type signatures
361 * @param returnType the return type signature
362 * @return the encoded method signature
366 public static char[] createMethodSignature(char[][] parameterTypes, char[] returnType) {
367 int parameterTypesLength = parameterTypes.length;
368 int parameterLength = 0;
369 for (int i = 0; i < parameterTypesLength; i++) {
370 parameterLength += parameterTypes[i].length;
373 int returnTypeLength = returnType.length;
374 char[] result = new char[1 + parameterLength + 1 + returnTypeLength];
375 result[0] = C_PARAM_START;
377 for (int i = 0; i < parameterTypesLength; i++) {
378 char[] parameterType = parameterTypes[i];
379 int length = parameterType.length;
380 System.arraycopy(parameterType, 0, result, index, length);
383 result[index] = C_PARAM_END;
384 System.arraycopy(returnType, 0, result, index+1, returnTypeLength);
388 * Creates a method signature from the given parameter and return type
389 * signatures. The encoded method signature is dot-based.
391 * @param parameterTypes the list of parameter type signatures
392 * @param returnType the return type signature
393 * @return the encoded method signature
395 public static String createMethodSignature(String[] parameterTypes, String returnType) {
396 int parameterTypesLenth = parameterTypes.length;
397 char[][] parameters = new char[parameterTypesLenth][];
398 for (int i = 0; i < parameterTypesLenth; i++) {
399 parameters[i] = parameterTypes[i].toCharArray();
401 return new String(createMethodSignature(parameters, returnType.toCharArray()));
404 * Creates a new type signature from the given type name encoded as a character
405 * array. This method is equivalent to
406 * <code>createTypeSignature(new String(typeName),isResolved)</code>, although
407 * more efficient for callers with character arrays rather than strings. If the
408 * type name is qualified, then it is expected to be dot-based.
410 * @param typeName the possibly qualified type name
411 * @param isResolved <code>true</code> if the type name is to be considered
412 * resolved (for example, a type name from a binary class file), and
413 * <code>false</code> if the type name is to be considered unresolved
414 * (for example, a type name found in source code)
415 * @return the encoded type signature
416 * @see #createTypeSignature(java.lang.String,boolean)
418 public static String createTypeSignature(char[] typeName, boolean isResolved) {
419 return new String(createCharArrayTypeSignature(typeName, isResolved));
422 * Creates a new type signature from the given type name encoded as a character
423 * array. This method is equivalent to
424 * <code>createTypeSignature(new String(typeName),isResolved).toCharArray()</code>, although
425 * more efficient for callers with character arrays rather than strings. If the
426 * type name is qualified, then it is expected to be dot-based.
428 * @param typeName the possibly qualified type name
429 * @param isResolved <code>true</code> if the type name is to be considered
430 * resolved (for example, a type name from a binary class file), and
431 * <code>false</code> if the type name is to be considered unresolved
432 * (for example, a type name found in source code)
433 * @return the encoded type signature
434 * @see #createTypeSignature(java.lang.String,boolean)
438 public static char[] createCharArrayTypeSignature(char[] typeName, boolean isResolved) {
440 Scanner scanner = new Scanner();
441 scanner.setSource(typeName);
442 int token = scanner.getNextToken();
443 boolean primitive = true;
444 char primitiveSig = ' ';
445 StringBuffer sig = null;
448 case ITerminalSymbols.TokenNameIdentifier :
449 char[] idSource = scanner.getCurrentIdentifierSource();
450 sig = new StringBuffer(idSource.length);
451 sig.append(idSource);
454 // case ITerminalSymbols.TokenNameboolean :
455 // primitiveSig = Signature.C_BOOLEAN;
457 // case ITerminalSymbols.TokenNamebyte :
458 // primitiveSig = Signature.C_BYTE;
460 // case ITerminalSymbols.TokenNamechar :
461 // primitiveSig = Signature.C_CHAR;
463 // case ITerminalSymbols.TokenNamedouble :
464 // primitiveSig = Signature.C_DOUBLE;
466 // case ITerminalSymbols.TokenNamefloat :
467 // primitiveSig = Signature.C_FLOAT;
469 // case ITerminalSymbols.TokenNameint :
470 // primitiveSig = Signature.C_INT;
472 // case ITerminalSymbols.TokenNamelong :
473 // primitiveSig = Signature.C_LONG;
475 // case ITerminalSymbols.TokenNameshort :
476 // primitiveSig = Signature.C_SHORT;
478 // case ITerminalSymbols.TokenNamevoid :
479 // primitiveSig = Signature.C_VOID;
482 throw new IllegalArgumentException();
484 token = scanner.getNextToken();
485 while (!primitive && token == ITerminalSymbols.TokenNameDOT) {
486 sig.append(scanner.getCurrentIdentifierSource());
487 token = scanner.getNextToken();
488 if (token == ITerminalSymbols.TokenNameIdentifier) {
489 sig.append(scanner.getCurrentIdentifierSource());
490 token = scanner.getNextToken();
492 throw new IllegalArgumentException();
495 while (token == ITerminalSymbols.TokenNameLBRACKET) {
496 token = scanner.getNextToken();
497 if (token != ITerminalSymbols.TokenNameRBRACKET)
498 throw new IllegalArgumentException();
500 token = scanner.getNextToken();
502 if (token != ITerminalSymbols.TokenNameEOF)
503 throw new IllegalArgumentException();
506 result = new char[arrayCount+1];
507 result[arrayCount] = primitiveSig;
509 int sigLength = sig.length();
510 int resultLength = arrayCount + 1 + sigLength + 1; // e.g. '[[[Ljava.lang.String;'
511 result = new char[resultLength];
512 sig.getChars(0, sigLength, result, arrayCount + 1);
513 result[arrayCount] = isResolved ? C_RESOLVED : C_UNRESOLVED;
514 result[resultLength-1] = C_NAME_END;
516 for (int i = 0; i < arrayCount; i++) {
520 } catch (InvalidInputException e) {
521 throw new IllegalArgumentException();
525 * Creates a new type signature from the given type name. If the type name is qualified,
526 * then it is expected to be dot-based.
531 * createTypeSignature("int", hucairz) -> "I"
532 * createTypeSignature("java.lang.String", true) -> "Ljava.lang.String;"
533 * createTypeSignature("String", false) -> "QString;"
534 * createTypeSignature("java.lang.String", false) -> "Qjava.lang.String;"
535 * createTypeSignature("int []", false) -> "[I"
540 * @param typeName the possibly qualified type name
541 * @param isResolved <code>true</code> if the type name is to be considered
542 * resolved (for example, a type name from a binary class file), and
543 * <code>false</code> if the type name is to be considered unresolved
544 * (for example, a type name found in source code)
545 * @return the encoded type signature
547 public static String createTypeSignature(String typeName, boolean isResolved) {
548 return createTypeSignature(typeName.toCharArray(), isResolved);
551 * Returns the array count (array nesting depth) of the given type signature.
553 * @param typeSignature the type signature
554 * @return the array nesting depth, or 0 if not an array
555 * @exception IllegalArgumentException if the signature is not syntactically
560 public static int getArrayCount(char[] typeSignature) throws IllegalArgumentException {
563 while (typeSignature[count] == C_ARRAY) {
567 } catch (ArrayIndexOutOfBoundsException e) { // signature is syntactically incorrect if last character is C_ARRAY
568 throw new IllegalArgumentException();
572 * Returns the array count (array nesting depth) of the given type signature.
574 * @param typeSignature the type signature
575 * @return the array nesting depth, or 0 if not an array
576 * @exception IllegalArgumentException if the signature is not syntactically
579 public static int getArrayCount(String typeSignature) throws IllegalArgumentException {
580 return getArrayCount(typeSignature.toCharArray());
583 * Returns the type signature without any array nesting.
588 * getElementType({'[', '[', 'I'}) --> {'I'}.
593 * @param typeSignature the type signature
594 * @return the type signature without arrays
595 * @exception IllegalArgumentException if the signature is not syntactically
600 public static char[] getElementType(char[] typeSignature) throws IllegalArgumentException {
601 int count = getArrayCount(typeSignature);
602 if (count == 0) return typeSignature;
603 int length = typeSignature.length;
604 char[] result = new char[length-count];
605 System.arraycopy(typeSignature, count, result, 0, length-count);
609 * Returns the type signature without any array nesting.
614 * getElementType("[[I") --> "I".
619 * @param typeSignature the type signature
620 * @return the type signature without arrays
621 * @exception IllegalArgumentException if the signature is not syntactically
624 public static String getElementType(String typeSignature) throws IllegalArgumentException {
625 return new String(getElementType(typeSignature.toCharArray()));
628 * Returns the number of parameter types in the given method signature.
630 * @param methodSignature the method signature
631 * @return the number of parameters
632 * @exception IllegalArgumentException if the signature is not syntactically
636 public static int getParameterCount(char[] methodSignature) throws IllegalArgumentException {
639 int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1;
641 throw new IllegalArgumentException();
643 char c = methodSignature[i++];
660 i = CharOperation.indexOf(C_SEMICOLON, methodSignature, i) + 1;
662 throw new IllegalArgumentException();
668 throw new IllegalArgumentException();
671 } catch (ArrayIndexOutOfBoundsException e) {
672 throw new IllegalArgumentException();
676 * Returns the number of parameter types in the given method signature.
678 * @param methodSignature the method signature
679 * @return the number of parameters
680 * @exception IllegalArgumentException if the signature is not syntactically
683 public static int getParameterCount(String methodSignature) throws IllegalArgumentException {
684 return getParameterCount(methodSignature.toCharArray());
687 * Extracts the parameter type signatures from the given method signature.
688 * The method signature is expected to be dot-based.
690 * @param methodSignature the method signature
691 * @return the list of parameter type signatures
692 * @exception IllegalArgumentException if the signature is syntactically
697 public static char[][] getParameterTypes(char[] methodSignature) throws IllegalArgumentException {
699 int count = getParameterCount(methodSignature);
700 char[][] result = new char[count][];
703 int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1;
707 char c = methodSignature[i++];
710 // array depth is i - start;
721 // common case of base types
722 if (i - start == 1) {
725 result[count++] = new char[] {C_BOOLEAN};
728 result[count++] = new char[] {C_BYTE};
731 result[count++] = new char[] {C_CHAR};
734 result[count++] = new char[] {C_DOUBLE};
737 result[count++] = new char[] {C_FLOAT};
740 result[count++] = new char[] {C_INT};
743 result[count++] = new char[] {C_LONG};
746 result[count++] = new char[] {C_SHORT};
749 result[count++] = new char[] {C_VOID};
753 result[count++] = CharOperation.subarray(methodSignature, start, i);
759 i = CharOperation.indexOf(C_SEMICOLON, methodSignature, i) + 1;
761 throw new IllegalArgumentException();
762 result[count++] = CharOperation.subarray(methodSignature, start, i);
768 throw new IllegalArgumentException();
771 } catch (ArrayIndexOutOfBoundsException e) {
772 throw new IllegalArgumentException();
776 * Extracts the parameter type signatures from the given method signature.
777 * The method signature is expected to be dot-based.
779 * @param methodSignature the method signature
780 * @return the list of parameter type signatures
781 * @exception IllegalArgumentException if the signature is syntactically
784 public static String[] getParameterTypes(String methodSignature) throws IllegalArgumentException {
785 char[][] parameterTypes = getParameterTypes(methodSignature.toCharArray());
786 int length = parameterTypes.length;
787 String[] result = new String[length];
788 for (int i = 0; i < length; i++) {
789 result[i] = new String(parameterTypes[i]);
794 * Returns a char array containing all but the last segment of the given
795 * dot-separated qualified name. Returns the empty char array if it is not qualified.
800 * getQualifier({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g'}
801 * getQualifier({'O', 'u', 't', 'e', 'r', '.', 'I', 'n', 'n', 'e', 'r'}) -> {'O', 'u', 't', 'e', 'r'}
806 * @param name the name
807 * @return the qualifier prefix, or the empty char array if the name contains no
812 public static char[] getQualifier(char[] name) {
813 int lastDot = CharOperation.lastIndexOf(C_DOT, name);
815 return NO_CHAR; //$NON-NLS-1$
817 return CharOperation.subarray(name, 0, lastDot);
820 * Returns a string containing all but the last segment of the given
821 * dot-separated qualified name. Returns the empty string if it is not qualified.
826 * getQualifier("java.lang.Object") -> "java.lang"
827 * getQualifier("Outer.Inner") -> "Outer"
832 * @param name the name
833 * @return the qualifier prefix, or the empty string if the name contains no
836 public static String getQualifier(String name) {
837 return new String(getQualifier(name.toCharArray()));
840 * Extracts the return type from the given method signature. The method signature is
841 * expected to be dot-based.
843 * @param methodSignature the method signature
844 * @return the type signature of the return type
845 * @exception IllegalArgumentException if the signature is syntactically
850 public static char[] getReturnType(char[] methodSignature) throws IllegalArgumentException {
851 int i = CharOperation.lastIndexOf(C_PARAM_END, methodSignature);
853 throw new IllegalArgumentException();
855 return CharOperation.subarray(methodSignature, i + 1, methodSignature.length);
858 * Extracts the return type from the given method signature. The method signature is
859 * expected to be dot-based.
861 * @param methodSignature the method signature
862 * @return the type signature of the return type
863 * @exception IllegalArgumentException if the signature is syntactically
866 public static String getReturnType(String methodSignature) throws IllegalArgumentException {
867 return new String(getReturnType(methodSignature.toCharArray()));
870 * Returns the last segment of the given dot-separated qualified name.
871 * Returns the given name if it is not qualified.
876 * getSimpleName({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'O', 'b', 'j', 'e', 'c', 't'}
881 * @param name the name
882 * @return the last segment of the qualified name
886 public static char[] getSimpleName(char[] name) {
887 int lastDot = CharOperation.lastIndexOf(C_DOT, name);
891 return CharOperation.subarray(name, lastDot + 1, name.length);
894 * Returns the last segment of the given dot-separated qualified name.
895 * Returns the given name if it is not qualified.
900 * getSimpleName("java.lang.Object") -> "Object"
905 * @param name the name
906 * @return the last segment of the qualified name
908 public static String getSimpleName(String name) {
909 return new String(getSimpleName(name.toCharArray()));
912 * Returns all segments of the given dot-separated qualified name.
913 * Returns an array with only the given name if it is not qualified.
914 * Returns an empty array if the name is empty.
919 * 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'}}
920 * getSimpleNames({'O', 'b', 'j', 'e', 'c', 't'}) -> {{'O', 'b', 'j', 'e', 'c', 't'}}
921 * getSimpleNames("") -> {}
925 * @param name the name
926 * @return the list of simple names, possibly empty
930 public static char[][] getSimpleNames(char[] name) {
931 if (name.length == 0) {
934 int dot = CharOperation.indexOf(C_DOT, name);
936 return new char[][] {name};
939 while ((dot = CharOperation.indexOf(C_DOT, name, dot + 1)) != -1) {
942 char[][] result = new char[n + 1][];
944 for (int i = 0; i < n; ++i) {
945 dot = CharOperation.indexOf(C_DOT, name, segStart);
946 result[i] = CharOperation.subarray(name, segStart, dot);
949 result[n] = CharOperation.subarray(name, segStart, name.length);
953 * Returns all segments of the given dot-separated qualified name.
954 * Returns an array with only the given name if it is not qualified.
955 * Returns an empty array if the name is empty.
960 * getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
961 * getSimpleNames("Object") -> {"Object"}
962 * getSimpleNames("") -> {}
966 * @param name the name
967 * @return the list of simple names, possibly empty
969 public static String[] getSimpleNames(String name) {
970 char[][] simpleNames = getSimpleNames(name.toCharArray());
971 int length = simpleNames.length;
972 String[] result = new String[length];
973 for (int i = 0; i < length; i++) {
974 result[i] = new String(simpleNames[i]);
979 * Converts the given method signature to a readable form. The method signature is expected to
985 * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
990 * @param methodSignature the method signature to convert
991 * @param methodName the name of the method to insert in the result, or
992 * <code>null</code> if no method name is to be included
993 * @param parameterNames the parameter names to insert in the result, or
994 * <code>null</code> if no parameter names are to be included; if supplied,
995 * the number of parameter names must match that of the method signature
996 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
997 * qualified, and <code>false</code> to use only simple names
998 * @param includeReturnType <code>true</code> if the return type is to be
1000 * @return the char array representation of the method signature
1004 public static char[] toCharArray(char[] methodSignature, char[] methodName, char[][] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
1006 int firstParen = CharOperation.indexOf(C_PARAM_START, methodSignature);
1007 if (firstParen == -1) throw new IllegalArgumentException();
1009 int sigLength = methodSignature.length;
1011 // compute result length
1016 int resultLength = 0;
1017 signature: for (int i = firstParen; i < sigLength; i++) {
1018 switch (methodSignature[i]) {
1020 resultLength += 2; // []
1023 resultLength += BOOLEAN.length;
1026 resultLength += BYTE.length;
1029 resultLength += CHAR.length;
1032 resultLength += DOUBLE.length;
1035 resultLength += FLOAT.length;
1038 resultLength += INT.length;
1041 resultLength += LONG.length;
1044 resultLength += SHORT.length;
1047 resultLength += VOID.length;
1051 int end = CharOperation.indexOf(C_SEMICOLON, methodSignature, i);
1052 if (end == -1) throw new IllegalArgumentException();
1054 if (fullyQualifyTypeNames) {
1057 start = CharOperation.lastIndexOf(C_DOT, methodSignature, i, end) + 1;
1058 if (start == 0) start = i+1;
1060 resultLength += end-start;
1063 case C_PARAM_START :
1064 // add space for "("
1069 if (includeReturnType) {
1070 if (paramCount > 0) {
1071 // remove space for ", " that was added with last parameter and remove space that is going to be added for ", " after return type
1072 // and add space for ") "
1075 // remove space that is going to be added for ", " after return type
1076 // and add space for ") "
1079 // decrement param count because it is going to be added for return type
1083 if (paramCount > 0) {
1084 // remove space for ", " that was added with last parameter and add space for ")"
1087 // add space for ")"
1093 throw new IllegalArgumentException();
1095 resultLength += 2; // add space for ", "
1100 int parameterNamesLength = parameterNames == null ? 0 : parameterNames.length;
1101 for (int i = 0; i <parameterNamesLength; i++) {
1102 resultLength += parameterNames[i].length + 1; // parameter name + space
1106 int selectorLength = methodName == null ? 0 : methodName.length;
1107 resultLength += selectorLength;
1109 // create resulting char array
1110 char[] result = new char[resultLength];
1114 if (includeReturnType) {
1115 long pos = copyType(methodSignature, lastParen+1, result, index, fullyQualifyTypeNames);
1116 index = (int) (pos >>> 32);
1117 result[index++] = ' ';
1121 if (methodName != null) {
1122 System.arraycopy(methodName, 0, result, index, selectorLength);
1123 index += selectorLength;
1127 result[index++] = C_PARAM_START;
1128 int sigPos = firstParen+1;
1129 for (int i = 0; i < paramCount; i++) {
1130 long pos = copyType(methodSignature, sigPos, result, index, fullyQualifyTypeNames);
1131 index = (int) (pos >>> 32);
1133 if (parameterNames != null) {
1134 result[index++] = ' ';
1135 char[] parameterName = parameterNames[i];
1136 int paramLength = parameterName.length;
1137 System.arraycopy(parameterName, 0, result, index, paramLength);
1138 index += paramLength;
1140 if (i != paramCount-1) {
1141 result[index++] = ',';
1142 result[index++] = ' ';
1145 if (sigPos >= sigLength) {
1146 throw new IllegalArgumentException(); // should be on last paren
1148 result[index++] = C_PARAM_END;
1151 } catch (ArrayIndexOutOfBoundsException e) {
1152 throw new IllegalArgumentException();
1156 * Converts the given type signature to a readable string. The signature is expected to
1163 * 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', '[', ']'}
1164 * toString({'I'}) -> {'i', 'n', 't'}
1169 * Note: This method assumes that a type signature containing a <code>'$'</code>
1170 * is an inner type signature. While this is correct in most cases, someone could
1171 * define a non-inner type name containing a <code>'$'</code>. Handling this
1172 * correctly in all cases would have required resolving the signature, which
1173 * generally not feasible.
1176 * @param signature the type signature
1177 * @return the string representation of the type
1178 * @exception IllegalArgumentException if the signature is not syntactically
1183 public static char[] toCharArray(char[] signature) throws IllegalArgumentException {
1185 int sigLength = signature.length;
1187 if (sigLength == 0 || signature[0] == C_PARAM_START) {
1188 return toCharArray(signature, NO_CHAR, null, true, true);
1191 // compute result length
1192 int resultLength = 0;
1194 while (signature[++index] == C_ARRAY) {
1195 resultLength += 2; // []
1197 switch (signature[index]) {
1199 resultLength += BOOLEAN.length;
1202 resultLength += BYTE.length;
1205 resultLength += CHAR.length;
1208 resultLength += DOUBLE.length;
1211 resultLength += FLOAT.length;
1214 resultLength += INT.length;
1217 resultLength += LONG.length;
1220 resultLength += SHORT.length;
1223 resultLength += VOID.length;
1227 int end = CharOperation.indexOf(C_SEMICOLON, signature, index);
1228 if (end == -1) throw new IllegalArgumentException();
1229 int start = index + 1;
1230 resultLength += end-start;
1233 throw new IllegalArgumentException();
1236 char[] result = new char[resultLength];
1237 copyType(signature, 0, result, 0, true);
1240 * Converts '$' separated type signatures into '.' separated type signature.
1241 * NOTE: This assumes that the type signature is an inner type signature.
1242 * This is true in most cases, but someone can define a non-inner type
1243 * name containing a '$'. However to tell the difference, we would have
1244 * to resolve the signature, which cannot be done at this point.
1246 CharOperation.replace(result, C_DOLLAR, C_DOT);
1249 } catch (ArrayIndexOutOfBoundsException e) {
1250 throw new IllegalArgumentException();
1254 * Converts the given array of qualified name segments to a qualified name.
1259 * 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'}
1260 * toQualifiedName({{'O', 'b', 'j', 'e', 'c', 't'}}) -> {'O', 'b', 'j', 'e', 'c', 't'}
1261 * toQualifiedName({{}}) -> {}
1266 * @param segments the list of name segments, possibly empty
1267 * @return the dot-separated qualified name, or the empty string
1271 public static char[] toQualifiedName(char[][] segments) {
1272 int length = segments.length;
1273 if (length == 0) return NO_CHAR;
1274 if (length == 1) return segments[0];
1276 int resultLength = 0;
1277 for (int i = 0; i < length; i++) {
1278 resultLength += segments[i].length+1;
1281 char[] result = new char[resultLength];
1283 for (int i = 0; i < length; i++) {
1284 char[] segment = segments[i];
1285 int segmentLength = segment.length;
1286 System.arraycopy(segment, 0, result, index, segmentLength);
1287 index += segmentLength;
1288 if (i != length-1) {
1289 result[index++] = C_DOT;
1295 * Converts the given array of qualified name segments to a qualified name.
1300 * toQualifiedName(new String[] {"java", "lang", "Object"}) -> "java.lang.Object"
1301 * toQualifiedName(new String[] {"Object"}) -> "Object"
1302 * toQualifiedName(new String[0]) -> ""
1307 * @param segments the list of name segments, possibly empty
1308 * @return the dot-separated qualified name, or the empty string
1310 public static String toQualifiedName(String[] segments) {
1311 int length = segments.length;
1312 char[][] charArrays = new char[length][];
1313 for (int i = 0; i < length; i++) {
1314 charArrays[i] = segments[i].toCharArray();
1316 return new String(toQualifiedName(charArrays));
1319 * Converts the given type signature to a readable string. The signature is expected to
1326 * toString("[Ljava.lang.String;") -> "java.lang.String[]"
1327 * toString("I") -> "int"
1332 * Note: This method assumes that a type signature containing a <code>'$'</code>
1333 * is an inner type signature. While this is correct in most cases, someone could
1334 * define a non-inner type name containing a <code>'$'</code>. Handling this
1335 * correctly in all cases would have required resolving the signature, which
1336 * generally not feasible.
1339 * @param signature the type signature
1340 * @return the string representation of the type
1341 * @exception IllegalArgumentException if the signature is not syntactically
1344 public static String toString(String signature) throws IllegalArgumentException {
1345 return new String(toCharArray(signature.toCharArray()));
1348 * Converts the given method signature to a readable string. The method signature is expected to
1354 * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
1359 * @param methodSignature the method signature to convert
1360 * @param methodName the name of the method to insert in the result, or
1361 * <code>null</code> if no method name is to be included
1362 * @param parameterNames the parameter names to insert in the result, or
1363 * <code>null</code> if no parameter names are to be included; if supplied,
1364 * the number of parameter names must match that of the method signature
1365 * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
1366 * qualified, and <code>false</code> to use only simple names
1367 * @param includeReturnType <code>true</code> if the return type is to be
1369 * @return the string representation of the method signature
1371 public static String toString(String methodSignature, String methodName, String[] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) {
1373 if (parameterNames == null) {
1376 int paramLength = parameterNames.length;
1377 params = new char[paramLength][];
1378 for (int i = 0; i < paramLength; i++) {
1379 params[i] = parameterNames[i].toCharArray();
1382 return new String(toCharArray(methodSignature.toCharArray(), methodName == null ? null : methodName.toCharArray(), params, fullyQualifyTypeNames, includeReturnType));