KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > core > Signature


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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 java.util.ArrayList JavaDoc;
15
16 import org.eclipse.jdt.core.compiler.CharOperation;
17 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
18 import org.eclipse.jdt.internal.core.util.Util;
19
20
21 /**
22  * Provides methods for encoding and decoding type and method signature strings.
23  * <p>
24  * Signatures obtained from parsing source files (i.e. files with one of the
25  * {@link JavaCore#getJavaLikeExtensions() Java-like extensions}) differ subtly
26  * from ones obtained from pre-compiled binary (".class") files in class names are
27  * usually left unresolved in the former. For example, the normal resolved form
28  * of the type "String" embeds the class's package name ("Ljava.lang.String;"
29  * or "Ljava/lang/String;"), whereas the unresolved form contains only what is
30  * written "QString;".
31  * </p>
32  * <p>
33  * Generic types introduce to the Java language in J2SE 1.5 add three new
34  * facets to signatures: type variables, parameterized types with type arguments,
35  * and formal type parameters. <i>Rich</i> signatures containing these facets
36  * only occur when dealing with code that makes overt use of the new language
37  * features. All other code, and certainly all Java code written or compiled
38  * with J2SE 1.4 or earlier, involved only <i>simple</i> signatures.
39  * </p>
40  * <p>
41  * Note that the "Q" and "!" formats are specific to Eclipse; the remainder
42  * are specified in the JVM spec.
43  * </p>
44  * <p>
45  * The syntax for a type signature is:
46  * <pre>
47  * TypeSignature ::=
48  * "B" // byte
49  * | "C" // char
50  * | "D" // double
51  * | "F" // float
52  * | "I" // int
53  * | "J" // long
54  * | "S" // short
55  * | "V" // void
56  * | "Z" // boolean
57  * | "T" + Identifier + ";" // type variable
58  * | "[" + TypeSignature // array X[]
59  * | "!" + TypeSignature // capture-of ?
60  * | ResolvedClassTypeSignature
61  * | UnresolvedClassTypeSignature
62  *
63  * ResolvedClassTypeSignature ::= // resolved named type (in compiled code)
64  * "L" + Identifier + OptionalTypeArguments
65  * ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
66  * | OptionalTypeParameters + "L" + Identifier +
67  * ( ( "." | "/" ) + Identifier )* + ";"
68  *
69  * UnresolvedClassTypeSignature ::= // unresolved named type (in source code)
70  * "Q" + Identifier + OptionalTypeArguments
71  * ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
72  * | OptionalTypeParameters "Q" + Identifier +
73  * ( ( "." | "/" ) + Identifier )* + ";"
74  *
75  * OptionalTypeArguments ::=
76  * "&lt;" + TypeArgument+ + "&gt;"
77  * |
78  *
79  * TypeArgument ::=
80  * | TypeSignature
81  * | "*" // wildcard ?
82  * | "+" TypeSignature // wildcard ? extends X
83  * | "-" TypeSignature // wildcard ? super X
84  *
85  * OptionalTypeParameters ::=
86  * "&lt;" + FormalTypeParameterSignature+ + "&gt;"
87  * |
88  * </pre>
89  * </p>
90  * <p>
91  * Examples:
92  * <ul>
93  * <li><code>"[[I"</code> denotes <code>int[][]</code></li>
94  * <li><code>"Ljava.lang.String;"</code> denotes <code>java.lang.String</code> in compiled code</li>
95  * <li><code>"QString;"</code> denotes <code>String</code> in source code</li>
96  * <li><code>"Qjava.lang.String;"</code> denotes <code>java.lang.String</code> in source code</li>
97  * <li><code>"[QString;"</code> denotes <code>String[]</code> in source code</li>
98  * <li><code>"QMap&lt;QString;*&gt;;"</code> denotes <code>Map&lt;String,?&gt;</code> in source code</li>
99  * <li><code>"Qjava.util.List&ltTV;&gt;;"</code> denotes <code>java.util.List&lt;V&gt;</code> in source code</li>
100  * <li><code>"&ltE;&gt;Ljava.util.List;"</code> denotes <code>&lt;E&gt;java.util.List</code> in source code</li>
101  * </ul>
102  * </p>
103  * <p>
104  * The syntax for a method signature is:
105  * <pre>
106  * MethodSignature ::= OptionalTypeParameters + "(" + ParamTypeSignature* + ")" + ReturnTypeSignature
107  * ParamTypeSignature ::= TypeSignature
108  * ReturnTypeSignature ::= TypeSignature
109  * </pre>
110  * <p>
111  * Examples:
112  * <ul>
113  * <li><code>"()I"</code> denotes <code>int foo()</code></li>
114  * <li><code>"([Ljava.lang.String;)V"</code> denotes <code>void foo(java.lang.String[])</code> in compiled code</li>
115  * <li><code>"(QString;)QObject;"</code> denotes <code>Object foo(String)</code> in source code</li>
116  * </ul>
117  * </p>
118  * <p>
119  * The syntax for a formal type parameter signature is:
120  * <pre>
121  * FormalTypeParameterSignature ::=
122  * TypeVariableName + OptionalClassBound + InterfaceBound*
123  * TypeVariableName ::= Identifier
124  * OptionalClassBound ::=
125  * ":"
126  * | ":" + TypeSignature
127  * InterfaceBound ::=
128  * ":" + TypeSignature
129  * </pre>
130  * <p>
131  * Examples:
132  * <ul>
133  * <li><code>"X:"</code> denotes <code>X</code></li>
134  * <li><code>"X:QReader;"</code> denotes <code>X extends Reader</code> in source code</li>
135  * <li><code>"X:QReader;:QSerializable;"</code> denotes <code>X extends Reader & Serializable</code> in source code</li>
136  * </ul>
137  * </p>
138  * <p>
139  * This class provides static methods and constants only; it is not intended to be
140  * instantiated or subclassed by clients.
141  * </p>
142  */

143 public final class Signature {
144
145     /**
146      * Character constant indicating the primitive type boolean in a signature.
147      * Value is <code>'Z'</code>.
148      */

149     public static final char C_BOOLEAN = 'Z';
150
151     /**
152      * Character constant indicating the primitive type byte in a signature.
153      * Value is <code>'B'</code>.
154      */

155     public static final char C_BYTE = 'B';
156
157     /**
158      * Character constant indicating the primitive type char in a signature.
159      * Value is <code>'C'</code>.
160      */

161     public static final char C_CHAR = 'C';
162
163     /**
164      * Character constant indicating the primitive type double in a signature.
165      * Value is <code>'D'</code>.
166      */

167     public static final char C_DOUBLE = 'D';
168
169     /**
170      * Character constant indicating the primitive type float in a signature.
171      * Value is <code>'F'</code>.
172      */

173     public static final char C_FLOAT = 'F';
174
175     /**
176      * Character constant indicating the primitive type int in a signature.
177      * Value is <code>'I'</code>.
178      */

179     public static final char C_INT = 'I';
180     
181     /**
182      * Character constant indicating the semicolon in a signature.
183      * Value is <code>';'</code>.
184      */

185     public static final char C_SEMICOLON = ';';
186
187     /**
188      * Character constant indicating the colon in a signature.
189      * Value is <code>':'</code>.
190      * @since 3.0
191      */

192     public static final char C_COLON = ':';
193
194     /**
195      * Character constant indicating the primitive type long in a signature.
196      * Value is <code>'J'</code>.
197      */

198     public static final char C_LONG = 'J';
199     
200     /**
201      * Character constant indicating the primitive type short in a signature.
202      * Value is <code>'S'</code>.
203      */

204     public static final char C_SHORT = 'S';
205     
206     /**
207      * Character constant indicating result type void in a signature.
208      * Value is <code>'V'</code>.
209      */

210     public static final char C_VOID = 'V';
211     
212     /**
213      * Character constant indicating the start of a resolved type variable in a
214      * signature. Value is <code>'T'</code>.
215      * @since 3.0
216      */

217     public static final char C_TYPE_VARIABLE = 'T';
218     
219     /**
220      * Character constant indicating an unbound wildcard type argument
221      * in a signature.
222      * Value is <code>'*'</code>.
223      * @since 3.0
224      */

225     public static final char C_STAR = '*';
226     
227     /**
228      * Character constant indicating an exception in a signature.
229      * Value is <code>'^'</code>.
230      * @since 3.1
231      */

232     public static final char C_EXCEPTION_START = '^';
233     
234     /**
235      * Character constant indicating a bound wildcard type argument
236      * in a signature with extends clause.
237      * Value is <code>'+'</code>.
238      * @since 3.1
239      */

240     public static final char C_EXTENDS = '+';
241
242     /**
243      * Character constant indicating a bound wildcard type argument
244      * in a signature with super clause.
245      * Value is <code>'-'</code>.
246      * @since 3.1
247      */

248     public static final char C_SUPER = '-';
249     
250     /**
251      * Character constant indicating the dot in a signature.
252      * Value is <code>'.'</code>.
253      */

254     public static final char C_DOT = '.';
255     
256     /**
257      * Character constant indicating the dollar in a signature.
258      * Value is <code>'$'</code>.
259      */

260     public static final char C_DOLLAR = '$';
261
262     /**
263      * Character constant indicating an array type in a signature.
264      * Value is <code>'['</code>.
265      */

266     public static final char C_ARRAY = '[';
267
268     /**
269      * Character constant indicating the start of a resolved, named type in a
270      * signature. Value is <code>'L'</code>.
271      */

272     public static final char C_RESOLVED = 'L';
273
274     /**
275      * Character constant indicating the start of an unresolved, named type in a
276      * signature. Value is <code>'Q'</code>.
277      */

278     public static final char C_UNRESOLVED = 'Q';
279
280     /**
281      * Character constant indicating the end of a named type in a signature.
282      * Value is <code>';'</code>.
283      */

284     public static final char C_NAME_END = ';';
285
286     /**
287      * Character constant indicating the start of a parameter type list in a
288      * signature. Value is <code>'('</code>.
289      */

290     public static final char C_PARAM_START = '(';
291
292     /**
293      * Character constant indicating the end of a parameter type list in a
294      * signature. Value is <code>')'</code>.
295      */

296     public static final char C_PARAM_END = ')';
297
298     /**
299      * Character constant indicating the start of a formal type parameter
300      * (or type argument) list in a signature. Value is <code>'&lt;'</code>.
301      * @since 3.0
302      */

303     public static final char C_GENERIC_START = '<';
304
305     /**
306      * Character constant indicating the end of a generic type list in a
307      * signature. Value is <code>'&gt;'</code>.
308      * @since 3.0
309      */

310     public static final char C_GENERIC_END = '>';
311
312     /**
313      * Character constant indicating a capture of a wildcard type in a
314      * signature. Value is <code>'!'</code>.
315      * @since 3.1
316      */

317     public static final char C_CAPTURE = '!';
318     
319     /**
320      * String constant for the signature of the primitive type boolean.
321      * Value is <code>"Z"</code>.
322      */

323     public static final String JavaDoc SIG_BOOLEAN = "Z"; //$NON-NLS-1$
324

325     /**
326      * String constant for the signature of the primitive type byte.
327      * Value is <code>"B"</code>.
328      */

329     public static final String JavaDoc SIG_BYTE = "B"; //$NON-NLS-1$
330

331     /**
332      * String constant for the signature of the primitive type char.
333      * Value is <code>"C"</code>.
334      */

335     public static final String JavaDoc SIG_CHAR = "C"; //$NON-NLS-1$
336

337     /**
338      * String constant for the signature of the primitive type double.
339      * Value is <code>"D"</code>.
340      */

341     public static final String JavaDoc SIG_DOUBLE = "D"; //$NON-NLS-1$
342

343     /**
344      * String constant for the signature of the primitive type float.
345      * Value is <code>"F"</code>.
346      */

347     public static final String JavaDoc SIG_FLOAT = "F"; //$NON-NLS-1$
348

349     /**
350      * String constant for the signature of the primitive type int.
351      * Value is <code>"I"</code>.
352      */

353     public static final String JavaDoc SIG_INT = "I"; //$NON-NLS-1$
354

355     /**
356      * String constant for the signature of the primitive type long.
357      * Value is <code>"J"</code>.
358      */

359     public static final String JavaDoc SIG_LONG = "J"; //$NON-NLS-1$
360

361     /**
362      * String constant for the signature of the primitive type short.
363      * Value is <code>"S"</code>.
364      */

365     public static final String JavaDoc SIG_SHORT = "S"; //$NON-NLS-1$
366

367     /** String constant for the signature of result type void.
368      * Value is <code>"V"</code>.
369      */

370     public static final String JavaDoc SIG_VOID = "V"; //$NON-NLS-1$
371

372
373     /**
374      * Kind constant for a class type signature.
375      * @see #getTypeSignatureKind(String)
376      * @since 3.0
377      */

378     public static final int CLASS_TYPE_SIGNATURE = 1;
379
380     /**
381      * Kind constant for a base (primitive or void) type signature.
382      * @see #getTypeSignatureKind(String)
383      * @since 3.0
384      */

385     public static final int BASE_TYPE_SIGNATURE = 2;
386
387     /**
388      * Kind constant for a type variable signature.
389      * @see #getTypeSignatureKind(String)
390      * @since 3.0
391      */

392     public static final int TYPE_VARIABLE_SIGNATURE = 3;
393
394     /**
395      * Kind constant for an array type signature.
396      * @see #getTypeSignatureKind(String)
397      * @since 3.0
398      */

399     public static final int ARRAY_TYPE_SIGNATURE = 4;
400     
401     /**
402      * Kind constant for a wildcard type signature.
403      * @see #getTypeSignatureKind(String)
404      * @since 3.1
405      */

406     public static final int WILDCARD_TYPE_SIGNATURE = 5;
407
408     /**
409      * Kind constant for the capture of a wildcard type signature.
410      * @see #getTypeSignatureKind(String)
411      * @since 3.1
412      */

413     public static final int CAPTURE_TYPE_SIGNATURE = 6;
414
415     private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$
416
private static final char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
417
private static final char[] CHAR = "char".toCharArray(); //$NON-NLS-1$
418
private static final char[] DOUBLE = "double".toCharArray(); //$NON-NLS-1$
419
private static final char[] FLOAT = "float".toCharArray(); //$NON-NLS-1$
420
private static final char[] INT = "int".toCharArray(); //$NON-NLS-1$
421
private static final char[] LONG = "long".toCharArray(); //$NON-NLS-1$
422
private static final char[] SHORT = "short".toCharArray(); //$NON-NLS-1$
423
private static final char[] VOID = "void".toCharArray(); //$NON-NLS-1$
424
private static final char[] EXTENDS = "extends".toCharArray(); //$NON-NLS-1$
425
private static final char[] SUPER = "super".toCharArray(); //$NON-NLS-1$
426
private static final char[] CAPTURE = "capture-of".toCharArray(); //$NON-NLS-1$
427

428 private Signature() {
429     // Not instantiable
430
}
431
432 private static int checkName(char[] name, char[] typeName, int pos, int length) {
433     if (CharOperation.fragmentEquals(name, typeName, pos, true)) {
434         pos += name.length;
435         if (pos == length) return pos;
436         char currentChar = typeName[pos];
437         switch (currentChar) {
438             case ' ' :
439             case '.' :
440             case '<' :
441             case '>' :
442             case '[' :
443             case ',' :
444                 return pos;
445             default:
446                 if (ScannerHelper.isWhitespace(currentChar))
447                     return pos;
448                 
449         }
450     }
451     return -1;
452 }
453
454 /**
455  * Creates a new type signature with the given amount of array nesting added
456  * to the given type signature.
457  *
458  * @param typeSignature the type signature
459  * @param arrayCount the desired number of levels of array nesting
460  * @return the encoded array type signature
461  *
462  * @since 2.0
463  */

464 public static char[] createArraySignature(char[] typeSignature, int arrayCount) {
465     if (arrayCount == 0) return typeSignature;
466     int sigLength = typeSignature.length;
467     char[] result = new char[arrayCount + sigLength];
468     for (int i = 0; i < arrayCount; i++) {
469         result[i] = C_ARRAY;
470     }
471     System.arraycopy(typeSignature, 0, result, arrayCount, sigLength);
472     return result;
473 }
474 /**
475  * Creates a new type signature with the given amount of array nesting added
476  * to the given type signature.
477  *
478  * @param typeSignature the type signature
479  * @param arrayCount the desired number of levels of array nesting
480  * @return the encoded array type signature
481  */

482 public static String JavaDoc createArraySignature(String JavaDoc typeSignature, int arrayCount) {
483     return new String JavaDoc(createArraySignature(typeSignature.toCharArray(), arrayCount));
484 }
485
486 /**
487  * Creates a method signature from the given parameter and return type
488  * signatures. The encoded method signature is dot-based.
489  *
490  * @param parameterTypes the list of parameter type signatures
491  * @param returnType the return type signature
492  * @return the encoded method signature
493  *
494  * @since 2.0
495  */

496 public static char[] createMethodSignature(char[][] parameterTypes, char[] returnType) {
497     int parameterTypesLength = parameterTypes.length;
498     int parameterLength = 0;
499     for (int i = 0; i < parameterTypesLength; i++) {
500         parameterLength += parameterTypes[i].length;
501         
502     }
503     int returnTypeLength = returnType.length;
504     char[] result = new char[1 + parameterLength + 1 + returnTypeLength];
505     result[0] = C_PARAM_START;
506     int index = 1;
507     for (int i = 0; i < parameterTypesLength; i++) {
508         char[] parameterType = parameterTypes[i];
509         int length = parameterType.length;
510         System.arraycopy(parameterType, 0, result, index, length);
511         index += length;
512     }
513     result[index] = C_PARAM_END;
514     System.arraycopy(returnType, 0, result, index+1, returnTypeLength);
515     return result;
516 }
517
518 /**
519  * Creates a method signature from the given parameter and return type
520  * signatures. The encoded method signature is dot-based. This method
521  * is equivalent to
522  * <code>createMethodSignature(parameterTypes, returnType)</code>.
523  *
524  * @param parameterTypes the list of parameter type signatures
525  * @param returnType the return type signature
526  * @return the encoded method signature
527  * @see Signature#createMethodSignature(char[][], char[])
528  */

529 public static String JavaDoc createMethodSignature(String JavaDoc[] parameterTypes, String JavaDoc returnType) {
530     int parameterTypesLenth = parameterTypes.length;
531     char[][] parameters = new char[parameterTypesLenth][];
532     for (int i = 0; i < parameterTypesLenth; i++) {
533         parameters[i] = parameterTypes[i].toCharArray();
534     }
535     return new String JavaDoc(createMethodSignature(parameters, returnType.toCharArray()));
536 }
537
538 /**
539  * Creates a new type parameter signature with the given name and bounds.
540  *
541  * @param typeParameterName the type parameter name
542  * @param boundSignatures the signatures of associated bounds or empty array if none
543  * @return the encoded type parameter signature
544  *
545  * @since 3.1
546  */

547 public static char[] createTypeParameterSignature(char[] typeParameterName, char[][] boundSignatures) {
548     int length = boundSignatures.length;
549     if (length == 0) {
550         return CharOperation.append(typeParameterName, C_COLON); // param signature with no bounds still gets trailing colon
551
}
552     int boundsSize = 0;
553     for (int i = 0; i < length; i++) {
554         boundsSize += boundSignatures[i].length + 1;
555     }
556     int nameLength = typeParameterName.length;
557     char[] result = new char[nameLength + boundsSize];
558     System.arraycopy(typeParameterName, 0, result, 0, nameLength);
559     int index = nameLength;
560     for (int i = 0; i < length; i++) {
561         result[index++] = C_COLON;
562         int boundLength = boundSignatures[i].length;
563         System.arraycopy(boundSignatures[i], 0, result, index, boundLength);
564         index += boundLength;
565     }
566     return result;
567 }
568
569 /**
570  * Creates a new type parameter signature with the given name and bounds.
571  *
572  * @param typeParameterName the type parameter name
573  * @param boundSignatures the signatures of associated bounds or empty array if none
574  * @return the encoded type parameter signature
575  *
576  * @since 3.1
577  */

578 public static String JavaDoc createTypeParameterSignature(String JavaDoc typeParameterName, String JavaDoc[] boundSignatures) {
579     int length = boundSignatures.length;
580     char[][] boundSignatureChars = new char[length][];
581     for (int i = 0; i < length; i++) {
582         boundSignatureChars[i] = boundSignatures[i].toCharArray();
583     }
584     return new String JavaDoc(createTypeParameterSignature(typeParameterName.toCharArray(), boundSignatureChars));
585 }
586
587 /**
588  * Creates a new type signature from the given type name encoded as a character
589  * array. The type name may contain primitive types, array types or parameterized types.
590  * This method is equivalent to
591  * <code>createTypeSignature(new String(typeName),isResolved)</code>, although
592  * more efficient for callers with character arrays rather than strings. If the
593  * type name is qualified, then it is expected to be dot-based.
594  *
595  * @param typeName the possibly qualified type name
596  * @param isResolved <code>true</code> if the type name is to be considered
597  * resolved (for example, a type name from a binary class file), and
598  * <code>false</code> if the type name is to be considered unresolved
599  * (for example, a type name found in source code)
600  * @return the encoded type signature
601  * @see #createTypeSignature(java.lang.String,boolean)
602  */

603 public static String JavaDoc createTypeSignature(char[] typeName, boolean isResolved) {
604     return new String JavaDoc(createCharArrayTypeSignature(typeName, isResolved));
605 }
606
607 /**
608  * Creates a new type signature from the given type name encoded as a character
609  * array. The type name may contain primitive types or array types or parameterized types.
610  * This method is equivalent to
611  * <code>createTypeSignature(new String(typeName),isResolved).toCharArray()</code>,
612  * although more efficient for callers with character arrays rather than strings.
613  * If the type name is qualified, then it is expected to be dot-based.
614  *
615  * @param typeName the possibly qualified type name
616  * @param isResolved <code>true</code> if the type name is to be considered
617  * resolved (for example, a type name from a binary class file), and
618  * <code>false</code> if the type name is to be considered unresolved
619  * (for example, a type name found in source code)
620  * @return the encoded type signature
621  * @see #createTypeSignature(java.lang.String,boolean)
622  *
623  * @since 2.0
624  */

625 public static char[] createCharArrayTypeSignature(char[] typeName, boolean isResolved) {
626     if (typeName == null) throw new IllegalArgumentException JavaDoc("null"); //$NON-NLS-1$
627
int length = typeName.length;
628     if (length == 0) throw new IllegalArgumentException JavaDoc(new String JavaDoc(typeName));
629     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(5);
630     int pos = encodeTypeSignature(typeName, 0, isResolved, length, buffer);
631     pos = consumeWhitespace(typeName, pos, length);
632     if (pos < length) throw new IllegalArgumentException JavaDoc(new String JavaDoc(typeName));
633     char[] result = new char[length = buffer.length()];
634     buffer.getChars(0, length, result, 0);
635     return result;
636 }
637 private static int consumeWhitespace(char[] typeName, int pos, int length) {
638     while (pos < length) {
639         char currentChar = typeName[pos];
640         if (currentChar != ' ' && !CharOperation.isWhitespace(currentChar)) {
641             break;
642         }
643         pos++;
644     }
645     return pos;
646 }
647 private static int encodeQualifiedName(char[] typeName, int pos, int length, StringBuffer JavaDoc buffer) {
648     int count = 0;
649     char lastAppendedChar = 0;
650     nameLoop: while (pos < length) {
651         char currentChar = typeName[pos];
652         switch (currentChar) {
653             case '<' :
654             case '>' :
655             case '[' :
656             case ',' :
657                 break nameLoop;
658             case '.' :
659                 buffer.append(C_DOT);
660                 lastAppendedChar = C_DOT;
661                 count++;
662                 break;
663             default:
664                 if (currentChar == ' ' || ScannerHelper.isWhitespace(currentChar)) {
665                     if (lastAppendedChar == C_DOT) { // allow spaces after a dot
666
pos = consumeWhitespace(typeName, pos, length) - 1; // will be incremented
667
break;
668                     }
669                     // allow spaces before a dot
670
int checkPos = checkNextChar(typeName, '.', pos, length, true);
671                     if (checkPos > 0) {
672                         buffer.append(C_DOT); // process dot immediately to avoid one iteration
673
lastAppendedChar = C_DOT;
674                         count++;
675                         pos = checkPos;
676                         break;
677                     }
678                     break nameLoop;
679                 }
680                 buffer.append(currentChar);
681                 lastAppendedChar = currentChar;
682                 count++;
683                 break;
684         }
685         pos++;
686     }
687     if (count == 0) throw new IllegalArgumentException JavaDoc(new String JavaDoc(typeName));
688     return pos;
689 }
690
691 private static int encodeArrayDimension(char[] typeName, int pos, int length, StringBuffer JavaDoc buffer) {
692     int checkPos;
693     while (pos < length && (checkPos = checkNextChar(typeName, '[', pos, length, true)) > 0) {
694         pos = checkNextChar(typeName, ']', checkPos, length, false);
695         buffer.append(C_ARRAY);
696     }
697     return pos;
698 }
699 private static int checkArrayDimension(char[] typeName, int pos, int length) {
700     int genericBalance = 0;
701     while (pos < length) {
702         switch(typeName[pos]) {
703             case '<' :
704                 genericBalance++;
705                 break;
706             case ',' :
707                 if (genericBalance == 0) return -1;
708                 break;
709             case '>':
710                 if (genericBalance == 0) return -1;
711                 genericBalance--;
712                 break;
713             case '[':
714                 if (genericBalance == 0) {
715                     return pos;
716                 }
717         }
718         pos++;
719     }
720     return -1;
721 }
722 private static int checkNextChar(char[] typeName, char expectedChar, int pos, int length, boolean isOptional) {
723     pos = consumeWhitespace(typeName, pos, length);
724     if (pos < length && typeName[pos] == expectedChar)
725         return pos + 1;
726     if (!isOptional) throw new IllegalArgumentException JavaDoc(new String JavaDoc(typeName));
727     return -1;
728 }
729
730 private static int encodeTypeSignature(char[] typeName, int start, boolean isResolved, int length, StringBuffer JavaDoc buffer) {
731     int pos = start;
732     pos = consumeWhitespace(typeName, pos, length);
733     if (pos >= length) throw new IllegalArgumentException JavaDoc(new String JavaDoc(typeName));
734     int checkPos;
735     char currentChar = typeName[pos];
736     switch (currentChar) {
737         // primitive type?
738
case 'b' :
739             checkPos = checkName(BOOLEAN, typeName, pos, length);
740             if (checkPos > 0) {
741                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
742                 buffer.append(C_BOOLEAN);
743                 return pos;
744             }
745             checkPos = checkName(BYTE, typeName, pos, length);
746             if (checkPos > 0) {
747                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
748                 buffer.append(C_BYTE);
749                 return pos;
750             }
751             break;
752         case 'd':
753             checkPos = checkName(DOUBLE, typeName, pos, length);
754             if (checkPos > 0) {
755                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
756                 buffer.append(C_DOUBLE);
757                 return pos;
758             }
759             break;
760         case 'f':
761             checkPos = checkName(FLOAT, typeName, pos, length);
762             if (checkPos > 0) {
763                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
764                 buffer.append(C_FLOAT);
765                 return pos;
766             }
767             break;
768         case 'i':
769             checkPos = checkName(INT, typeName, pos, length);
770             if (checkPos > 0) {
771                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
772                 buffer.append(C_INT);
773                 return pos;
774             }
775             break;
776         case 'l':
777             checkPos = checkName(LONG, typeName, pos, length);
778             if (checkPos > 0) {
779                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
780                 buffer.append(C_LONG);
781                 return pos;
782             }
783             break;
784         case 's':
785             checkPos = checkName(SHORT, typeName, pos, length);
786             if (checkPos > 0) {
787                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
788                 buffer.append(C_SHORT);
789                 return pos;
790             }
791             break;
792         case 'v':
793             checkPos = checkName(VOID, typeName, pos, length);
794             if (checkPos > 0) {
795                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
796                 buffer.append(C_VOID);
797                 return pos;
798             }
799             break;
800         case 'c':
801             checkPos = checkName(CHAR, typeName, pos, length);
802             if (checkPos > 0) {
803                 pos = encodeArrayDimension(typeName, checkPos, length, buffer);
804                 buffer.append(C_CHAR);
805                 return pos;
806             } else {
807                 checkPos = checkName(CAPTURE, typeName, pos, length);
808                 if (checkPos > 0) {
809                     pos = consumeWhitespace(typeName, checkPos, length);
810                     if (typeName[pos] != '?') {
811                         break;
812                     }
813                 } else {
814                     break;
815                 }
816             }
817             buffer.append(C_CAPTURE);
818             // fall-thru for wildcard part of capture typecheckPos
819
case '?':
820             // wildcard
821
pos = consumeWhitespace(typeName, pos+1, length);
822             checkPos = checkName(EXTENDS, typeName, pos, length);
823             if (checkPos > 0) {
824                 buffer.append(C_EXTENDS);
825                 pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
826                 return pos;
827             }
828             checkPos = checkName(SUPER, typeName, pos, length);
829             if (checkPos > 0) {
830                 buffer.append(C_SUPER);
831                 pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
832                 return pos;
833             }
834             buffer.append(C_STAR);
835             return pos;
836     }
837     // non primitive type
838
checkPos = checkArrayDimension(typeName, pos, length);
839     int end;
840     if (checkPos > 0) {
841         end = encodeArrayDimension(typeName, checkPos, length, buffer);
842     } else {
843         end = -1;
844     }
845     buffer.append(isResolved ? C_RESOLVED : C_UNRESOLVED);
846     while (true) { // loop on qualifiedName[<args>][.qualifiedName[<args>]*
847
pos = encodeQualifiedName(typeName, pos, length, buffer);
848         checkPos = checkNextChar(typeName, '<', pos, length, true);
849         if (checkPos > 0) {
850             buffer.append(C_GENERIC_START);
851             pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
852             while ((checkPos = checkNextChar(typeName, ',', pos, length, true)) > 0) {
853                 pos = encodeTypeSignature(typeName, checkPos, isResolved, length, buffer);
854             }
855             pos = checkNextChar(typeName, '>', pos, length, false);
856             buffer.append(C_GENERIC_END);
857         }
858         checkPos = checkNextChar(typeName, '.', pos, length, true);
859         if (checkPos > 0) {
860             buffer.append(C_DOT);
861             pos = checkPos;
862         } else {
863             break;
864         }
865     }
866     buffer.append(C_NAME_END);
867     if (end > 0) pos = end; // skip array dimension which were preprocessed
868
return pos;
869 }
870
871 /**
872  * Creates a new type signature from the given type name. If the type name is qualified,
873  * then it is expected to be dot-based. The type name may contain primitive
874  * types or array types. However, parameterized types are not supported.
875  * <p>
876  * For example:
877  * <pre>
878  * <code>
879  * createTypeSignature("int", hucairz) -> "I"
880  * createTypeSignature("java.lang.String", true) -> "Ljava.lang.String;"
881  * createTypeSignature("String", false) -> "QString;"
882  * createTypeSignature("java.lang.String", false) -> "Qjava.lang.String;"
883  * createTypeSignature("int []", false) -> "[I"
884  * </code>
885  * </pre>
886  * </p>
887  *
888  * @param typeName the possibly qualified type name
889  * @param isResolved <code>true</code> if the type name is to be considered
890  * resolved (for example, a type name from a binary class file), and
891  * <code>false</code> if the type name is to be considered unresolved
892  * (for example, a type name found in source code)
893  * @return the encoded type signature
894  */

895 public static String JavaDoc createTypeSignature(String JavaDoc typeName, boolean isResolved) {
896     return createTypeSignature(typeName == null ? null : typeName.toCharArray(), isResolved);
897 }
898
899 /**
900  * Returns the array count (array nesting depth) of the given type signature.
901  *
902  * @param typeSignature the type signature
903  * @return the array nesting depth, or 0 if not an array
904  * @exception IllegalArgumentException if the signature is not syntactically
905  * correct
906  *
907  * @since 2.0
908  */

909 public static int getArrayCount(char[] typeSignature) throws IllegalArgumentException JavaDoc {
910     try {
911         int count = 0;
912         while (typeSignature[count] == C_ARRAY) {
913             ++count;
914         }
915         return count;
916     } catch (ArrayIndexOutOfBoundsException JavaDoc e) { // signature is syntactically incorrect if last character is C_ARRAY
917