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