KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > libraries > asm > util > CheckCodeAdapter


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31 package oracle.toplink.libraries.asm.util;
32
33 import oracle.toplink.libraries.asm.Label;
34 import oracle.toplink.libraries.asm.CodeAdapter;
35 import oracle.toplink.libraries.asm.CodeVisitor;
36 import oracle.toplink.libraries.asm.Constants;
37 import oracle.toplink.libraries.asm.Attribute;
38 import oracle.toplink.libraries.asm.Type;
39
40 import java.util.HashMap JavaDoc;
41
42 /**
43  * A {@link CodeAdapter CodeAdapter} that checks that its methods are properly
44  * used. More precisely this code adapter checks each instruction individually
45  * (i.e., each visit method checks some preconditions based <i>only</i> on its
46  * arguments - such as the fact that the given opcode is correct for a given
47  * visit method), but does <i>not</i> check the <i>sequence</i> of instructions.
48  * For example, in a method whose signature is <tt>void m ()</tt>, the invalid
49  * instruction IRETURN, or the invalid sequence IADD L2I will <i>not</i> be
50  * detected by this code adapter.
51  *
52  * @author Eric Bruneton
53  */

54
55 public class CheckCodeAdapter extends CodeAdapter {
56
57   /**
58    * <tt>true</tt> if the visitMaxs method has been called.
59    */

60
61   private boolean end;
62
63   /**
64    * The already visited labels. This map associate Integer values to Label
65    * keys.
66    */

67
68   private HashMap JavaDoc labels;
69
70   /**
71    * Code of the visit method to be used for each opcode.
72    */

73
74   private final static int[] TYPE = new int[] {
75     0, //NOP
76
0, //ACONST_NULL
77
0, //ICONST_M1
78
0, //ICONST_0
79
0, //ICONST_1
80
0, //ICONST_2
81
0, //ICONST_3
82
0, //ICONST_4
83
0, //ICONST_5
84
0, //LCONST_0
85
0, //LCONST_1
86
0, //FCONST_0
87
0, //FCONST_1
88
0, //FCONST_2
89
0, //DCONST_0
90
0, //DCONST_1
91
1, //BIPUSH
92
1, //SIPUSH
93
7, //LDC
94
-1, //LDC_W
95
-1, //LDC2_W
96
2, //ILOAD
97
2, //LLOAD
98
2, //FLOAD
99
2, //DLOAD
100
2, //ALOAD
101
-1, //ILOAD_0
102
-1, //ILOAD_1
103
-1, //ILOAD_2
104
-1, //ILOAD_3
105
-1, //LLOAD_0
106
-1, //LLOAD_1
107
-1, //LLOAD_2
108
-1, //LLOAD_3
109
-1, //FLOAD_0
110
-1, //FLOAD_1
111
-1, //FLOAD_2
112
-1, //FLOAD_3
113
-1, //DLOAD_0
114
-1, //DLOAD_1
115
-1, //DLOAD_2
116
-1, //DLOAD_3
117
-1, //ALOAD_0
118
-1, //ALOAD_1
119
-1, //ALOAD_2
120
-1, //ALOAD_3
121
0, //IALOAD
122
0, //LALOAD
123
0, //FALOAD
124
0, //DALOAD
125
0, //AALOAD
126
0, //BALOAD
127
0, //CALOAD
128
0, //SALOAD
129
2, //ISTORE
130
2, //LSTORE
131
2, //FSTORE
132
2, //DSTORE
133
2, //ASTORE
134
-1, //ISTORE_0
135
-1, //ISTORE_1
136
-1, //ISTORE_2
137
-1, //ISTORE_3
138
-1, //LSTORE_0
139
-1, //LSTORE_1
140
-1, //LSTORE_2
141
-1, //LSTORE_3
142
-1, //FSTORE_0
143
-1, //FSTORE_1
144
-1, //FSTORE_2
145
-1, //FSTORE_3
146
-1, //DSTORE_0
147
-1, //DSTORE_1
148
-1, //DSTORE_2
149
-1, //DSTORE_3
150
-1, //ASTORE_0
151
-1, //ASTORE_1
152
-1, //ASTORE_2
153
-1, //ASTORE_3
154
0, //IASTORE
155
0, //LASTORE
156
0, //FASTORE
157
0, //DASTORE
158
0, //AASTORE
159
0, //BASTORE
160
0, //CASTORE
161
0, //SASTORE
162
0, //POP
163
0, //POP2
164
0, //DUP
165
0, //DUP_X1
166
0, //DUP_X2
167
0, //DUP2
168
0, //DUP2_X1
169
0, //DUP2_X2
170
0, //SWAP
171
0, //IADD
172
0, //LADD
173
0, //FADD
174
0, //DADD
175
0, //ISUB
176
0, //LSUB
177
0, //FSUB
178
0, //DSUB
179
0, //IMUL
180
0, //LMUL
181
0, //FMUL
182
0, //DMUL
183
0, //IDIV
184
0, //LDIV
185
0, //FDIV
186
0, //DDIV
187
0, //IREM
188
0, //LREM
189
0, //FREM
190
0, //DREM
191
0, //INEG
192
0, //LNEG
193
0, //FNEG
194
0, //DNEG
195
0, //ISHL
196
0, //LSHL
197
0, //ISHR
198
0, //LSHR
199
0, //IUSHR
200
0, //LUSHR
201
0, //IAND
202
0, //LAND
203
0, //IOR
204
0, //LOR
205
0, //IXOR
206
0, //LXOR
207
8, //IINC
208
0, //I2L
209
0, //I2F
210
0, //I2D
211
0, //L2I
212
0, //L2F
213
0, //L2D
214
0, //F2I
215
0, //F2L
216
0, //F2D
217
0, //D2I
218
0, //D2L
219
0, //D2F
220
0, //I2B
221
0, //I2C
222
0, //I2S
223
0, //LCMP
224
0, //FCMPL
225
0, //FCMPG
226
0, //DCMPL
227
0, //DCMPG
228
6, //IFEQ
229
6, //IFNE
230
6, //IFLT
231
6, //IFGE
232
6, //IFGT
233
6, //IFLE
234
6, //IF_ICMPEQ
235
6, //IF_ICMPNE
236
6, //IF_ICMPLT
237
6, //IF_ICMPGE
238
6, //IF_ICMPGT
239
6, //IF_ICMPLE
240
6, //IF_ACMPEQ
241
6, //IF_ACMPNE
242
6, //GOTO
243
6, //JSR
244
2, //RET
245
9, //TABLESWITCH
246
10, //LOOKUPSWITCH
247
0, //IRETURN
248
0, //LRETURN
249
0, //FRETURN
250
0, //DRETURN
251
0, //ARETURN
252
0, //RETURN
253
4, //GETSTATIC
254
4, //PUTSTATIC
255
4, //GETFIELD
256
4, //PUTFIELD
257
5, //INVOKEVIRTUAL
258
5, //INVOKESPECIAL
259
5, //INVOKESTATIC
260
5, //INVOKEINTERFACE
261
-1, //UNUSED
262
3, //NEW
263
1, //NEWARRAY
264
3, //ANEWARRAY
265
0, //ARRAYLENGTH
266
0, //ATHROW
267
3, //CHECKCAST
268
3, //INSTANCEOF
269
0, //MONITORENTER
270
0, //MONITOREXIT
271
-1, //WIDE
272
11, //MULTIANEWARRAY
273
6, //IFNULL
274
6, //IFNONNULL
275
-1, //GOTO_W
276
-1 //JSR_W
277
};
278
279   /**
280    * Constructs a new {@link CheckCodeAdapter CheckCodeAdapter} object.
281    *
282    * @param cv the code visitor to which this adapter must delegate calls.
283    */

284
285   public CheckCodeAdapter (final CodeVisitor cv) {
286     super(cv);
287     this.labels = new HashMap JavaDoc();
288   }
289
290   public void visitInsn (final int opcode) {
291     checkEnd();
292     checkOpcode(opcode, 0);
293     cv.visitInsn(opcode);
294   }
295
296   public void visitIntInsn (final int opcode, final int operand) {
297     checkEnd();
298     checkOpcode(opcode, 1);
299     switch (opcode) {
300       case Constants.BIPUSH:
301         checkSignedByte(operand, "Invalid operand");
302         break;
303       case Constants.SIPUSH:
304         checkSignedShort(operand, "Invalid operand");
305         break;
306       //case Constants.NEWARRAY:
307
default:
308         if (operand < Constants.T_BOOLEAN || operand > Constants.T_LONG) {
309           throw new IllegalArgumentException JavaDoc(
310             "Invalid operand (must be an array type code T_...): " + operand);
311         }
312     }
313     cv.visitIntInsn(opcode, operand);
314   }
315
316   public void visitVarInsn (final int opcode, final int var) {
317     checkEnd();
318     checkOpcode(opcode, 2);
319     checkUnsignedShort(var, "Invalid variable index");
320     cv.visitVarInsn(opcode, var);
321   }
322
323   public void visitTypeInsn (final int opcode, final String JavaDoc desc) {
324     checkEnd();
325     checkOpcode(opcode, 3);
326     if (desc != null && desc.length() > 0 && desc.charAt(0) == '[') {
327       checkDesc(desc, false);
328     } else {
329       checkInternalName(desc, "type");
330     }
331     if (opcode == Constants.NEW && desc.charAt(0) == '[') {
332       throw new IllegalArgumentException JavaDoc(
333         "NEW cannot be used to create arrays: " + desc);
334     }
335     cv.visitTypeInsn(opcode, desc);
336   }
337
338   public void visitFieldInsn (
339     final int opcode,
340     final String JavaDoc owner,
341     final String JavaDoc name,
342     final String JavaDoc desc)
343   {
344     checkEnd();
345     checkOpcode(opcode, 4);
346     checkInternalName(owner, "owner");
347     checkIdentifier(name, "name");
348     checkDesc(desc, false);
349     cv.visitFieldInsn(opcode, owner, name, desc);
350   }
351
352   public void visitMethodInsn (
353     final int opcode,
354     final String JavaDoc owner,
355     final String JavaDoc name,
356     final String JavaDoc desc)
357   {
358     checkEnd();
359     checkOpcode(opcode, 5);
360     checkInternalName(owner, "owner");
361     checkMethodIdentifier(name, "name");
362     checkMethodDesc(desc);
363     cv.visitMethodInsn(opcode, owner, name, desc);
364   }
365
366   public void visitJumpInsn (final int opcode, final Label label) {
367     checkEnd();
368     checkOpcode(opcode, 6);
369     checkLabel(label, false, "label");
370     cv.visitJumpInsn(opcode, label);
371   }
372
373   public void visitLabel (final Label label) {
374     checkEnd();
375     checkLabel(label, false, "label");
376     if (labels.get(label) != null) {
377       throw new IllegalArgumentException JavaDoc("Already visited label");
378     } else {
379       labels.put(label, new Integer JavaDoc(labels.size()));
380     }
381     cv.visitLabel(label);
382   }
383
384   public void visitLdcInsn (final Object JavaDoc cst) {
385     checkEnd();
386     if (!(cst instanceof Type)) {
387       checkConstant(cst);
388     }
389     cv.visitLdcInsn(cst);
390   }
391
392   public void visitIincInsn (final int var, final int increment) {
393     checkEnd();
394     checkUnsignedShort(var, "Invalid variable index");
395     checkSignedShort(increment, "Invalid increment");
396     cv.visitIincInsn(var, increment);
397   }
398
399   public void visitTableSwitchInsn (
400     final int min,
401     final int max,
402     final Label dflt,
403     final Label labels[])
404   {
405     checkEnd();
406     if (max < min) {
407       throw new IllegalArgumentException JavaDoc(
408         "Max = " + max + " must be greater than or equal to min = " + min);
409     }
410     checkLabel(dflt, false, "default label");
411     if (labels == null || labels.length != max - min + 1) {
412       throw new IllegalArgumentException JavaDoc(
413         "There must be max - min + 1 labels");
414     }
415     for (int i = 0; i < labels.length; ++i) {
416       checkLabel(labels[i], false, "label at index " + i);
417     }
418     cv.visitTableSwitchInsn(min, max, dflt, labels);
419   }
420
421   public void visitLookupSwitchInsn (
422     final Label dflt,
423     final int keys[],
424     final Label labels[])
425   {
426     checkEnd();
427     checkLabel(dflt, false, "default label");
428     if (keys == null || labels == null || keys.length != labels.length) {
429       throw new IllegalArgumentException JavaDoc(
430         "There must be the same number of keys and labels");
431     }
432     for (int i = 0; i < labels.length; ++i) {
433       checkLabel(labels[i], false, "label at index " + i);
434     }
435     cv.visitLookupSwitchInsn(dflt, keys, labels);
436   }
437
438   public void visitMultiANewArrayInsn (final String JavaDoc desc, final int dims) {
439     checkEnd();
440     checkDesc(desc, false);
441     if (desc.charAt(0) != '[') {
442       throw new IllegalArgumentException JavaDoc(
443         "Invalid descriptor (must be an array type descriptor): " + desc);
444     }
445     if (dims < 1) {
446       throw new IllegalArgumentException JavaDoc(
447         "Invalid dimensions (must be greater than 0): " + dims);
448     }
449     if (dims > desc.lastIndexOf('[') + 1) {
450       throw new IllegalArgumentException JavaDoc(
451         "Invalid dimensions (must not be greater than dims(desc)): " + dims);
452     }
453     cv.visitMultiANewArrayInsn(desc, dims);
454   }
455
456   public void visitTryCatchBlock (
457     final Label start,
458     final Label end,
459     final Label handler,
460     final String JavaDoc type)
461   {
462     checkLabel(start, true, "start label");
463     checkLabel(end, true, "end label");
464     checkLabel(handler, true, "handler label");
465     if (type != null) {
466       checkInternalName(type, "type");
467     }
468     int s = ((Integer JavaDoc)labels.get(start)).intValue();
469     int e = ((Integer JavaDoc)labels.get(end)).intValue();
470     if (e <= s) {
471       throw new IllegalArgumentException JavaDoc(
472         "Invalid start and end labels (end must be greater than start)");
473     }
474     cv.visitTryCatchBlock(start, end, handler, type);
475   }
476
477   public void visitMaxs (final int maxStack, final int maxLocals) {
478     checkEnd();
479     end = true;
480     checkUnsignedShort(maxStack, "Invalid max stack");
481     checkUnsignedShort(maxLocals, "Invalid max locals");
482     cv.visitMaxs(maxStack, maxLocals);
483   }
484
485   public void visitLocalVariable (
486     final String JavaDoc name,
487     final String JavaDoc desc,
488     final Label start,
489     final Label end,
490     final int index)
491   {
492     checkIdentifier(name, "name");
493     checkDesc(desc, false);
494     checkLabel(start, true, "start label");
495     checkLabel(end, true, "end label");
496     checkUnsignedShort(index, "Invalid variable index");
497     int s = ((Integer JavaDoc)labels.get(start)).intValue();
498     int e = ((Integer JavaDoc)labels.get(end)).intValue();
499     if (e <= s) {
500       throw new IllegalArgumentException JavaDoc(
501         "Invalid start and end labels (end must be greater than start)");
502     }
503     cv.visitLocalVariable(name, desc, start, end, index);
504   }
505
506   public void visitLineNumber (final int line, final Label start) {
507     checkUnsignedShort(line, "Invalid line number");
508     checkLabel(start, true, "start label");
509     cv.visitLineNumber(line, start);
510   }
511
512   public void visitAttribute (Attribute attr) {
513     if (attr == null) {
514       throw new IllegalArgumentException JavaDoc(
515         "Invalid attribute (must not be null)");
516     }
517   }
518
519   // ---------------------------------------------------------------------------
520

521   /**
522    * Checks that the visitMaxs method has not been called.
523    */

524
525   void checkEnd () {
526     if (end) {
527       throw new IllegalStateException JavaDoc(
528         "Cannot visit instructions after visitMaxs has been called.");
529     }
530   }
531
532   /**
533    * Checks that the type of the given opcode is equal to the given type.
534    *
535    * @param opcode the opcode to be checked.
536    * @param type the expected opcode type.
537    */

538
539   static void checkOpcode (final int opcode, final int type) {
540     if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
541       throw new IllegalArgumentException JavaDoc("Invalid opcode: " + opcode);
542     }
543   }
544
545   /**
546    * Checks that the given value is a signed byte.
547    *
548    * @param value the value to be checked.
549    * @param msg an message to be used in case of error.
550    */

551
552   static void checkSignedByte (final int value, final String JavaDoc msg) {
553     if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
554       throw new IllegalArgumentException JavaDoc(
555         msg + " (must be a signed byte): " + value);
556     }
557   }
558
559   /**
560    * Checks that the given value is a signed short.
561    *
562    * @param value the value to be checked.
563    * @param msg an message to be used in case of error.
564    */

565
566   static void checkSignedShort (final int value, final String JavaDoc msg) {
567     if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
568       throw new IllegalArgumentException JavaDoc(
569         msg + " (must be a signed short): " + value);
570     }
571   }
572
573   /**
574    * Checks that the given value is an unsigned short.
575    *
576    * @param value the value to be checked.
577    * @param msg an message to be used in case of error.
578    */

579
580   static void checkUnsignedShort (final int value, final String JavaDoc msg) {
581     if (value < 0 || value > 65535) {
582       throw new IllegalArgumentException JavaDoc(
583         msg + " (must be an unsigned short): " + value);
584     }
585   }
586
587   /**
588    * Checks that the given value is an {@link java.lang.Integer Integer}, a
589    * {@link java.lang.Float Float}, a {@link java.lang.Long Long}, a {@link
590    * java.lang.Double Double} or a {@link String String}.
591    *
592    * @param cst the value to be checked.
593    */

594
595   static void checkConstant (final Object JavaDoc cst) {
596     if (!(cst instanceof Integer JavaDoc) &&
597       !(cst instanceof Float JavaDoc) &&
598       !(cst instanceof Long JavaDoc) &&
599       !(cst instanceof Double JavaDoc) &&
600       !(cst instanceof String JavaDoc))
601     {
602       throw new IllegalArgumentException JavaDoc("Invalid constant: " + cst);
603     }
604   }
605
606   /**
607    * Checks that the given string is a valid Java identifier.
608    *
609    * @param name the string to be checked.
610    * @param msg a message to be used in case of error.
611    */

612
613   static void checkIdentifier (final String JavaDoc name, final String JavaDoc msg) {
614     checkIdentifier(name, 0, -1, msg);
615   }
616
617   /**
618    * Checks that the given substring is a valid Java identifier.
619    *
620    * @param name the string to be checked.
621    * @param start index of the first character of the identifier (inclusive).
622    * @param end index of the last character of the identifier (exclusive). -1 is
623    * equivalent to <tt>name.length()</tt> if name is not <tt>null</tt>.
624    * @param msg a message to be used in case of error.
625    */

626
627   static void checkIdentifier (
628     final String JavaDoc name,
629     final int start,
630     final int end,
631     final String JavaDoc msg)
632   {
633     if (name == null || (end == -1 ? name.length() <= start : end <= start)) {
634       throw new IllegalArgumentException JavaDoc(
635         "Invalid " + msg + " (must not be null or empty)");
636     }
637     if (!Character.isJavaIdentifierStart(name.charAt(start))) {
638       throw new IllegalArgumentException JavaDoc(
639         "Invalid " + msg + " (must be a valid Java identifier): " + name);
640     }
641     int max = (end == -1 ? name.length() : end);
642     for (int i = start + 1; i < max; ++i) {
643       if (!Character.isJavaIdentifierPart(name.charAt(i))) {
644         throw new IllegalArgumentException JavaDoc(
645           "Invalid " + msg + " (must be a valid Java identifier): " + name);
646       }
647     }
648   }
649
650   /**
651    * Checks that the given string is a valid Java identifier or is equal to
652    * '&lt;init&gt;' or '&lt;clinit&gt;'.
653    *
654    * @param name the string to be checked.
655    * @param msg a message to be used in case of error.
656    */

657
658   static void checkMethodIdentifier (final String JavaDoc name, final String JavaDoc msg) {
659     if (name == null || name.length() == 0) {
660       throw new IllegalArgumentException JavaDoc(
661         "Invalid " + msg + " (must not be null or empty)");
662     }
663     if (name.equals("<init>") || name.equals("<clinit>")) {
664       return;
665     }
666     if (!Character.isJavaIdentifierStart(name.charAt(0))) {
667       throw new IllegalArgumentException JavaDoc(
668         "Invalid " + msg +
669         " (must be a '<init>', '<clinit>' or a valid Java identifier): " +
670         name);
671     }
672     for (int i = 1; i < name.length(); ++i) {
673       if (!Character.isJavaIdentifierPart(name.charAt(i))) {
674         throw new IllegalArgumentException JavaDoc(
675           "Invalid " + msg +
676           " (must be '<init>' or '<clinit>' or a valid Java identifier): " +
677           name);
678       }
679     }
680   }
681
682   /**
683    * Checks that the given string is a valid internal class name.
684    *
685    * @param name the string to be checked.
686    * @param msg a message to be used in case of error.
687    */

688
689   static void checkInternalName (final String JavaDoc name, final String JavaDoc msg) {
690     checkInternalName(name, 0, -1, msg);
691   }
692
693   /**
694    * Checks that the given substring is a valid internal class name.
695    *
696    * @param name the string to be checked.
697    * @param start index of the first character of the identifier (inclusive).
698    * @param end index of the last character of the identifier (exclusive). -1 is
699    * equivalent to <tt>name.length()</tt> if name is not <tt>null</tt>.
700    * @param msg a message to be used in case of error.
701    */

702
703   static void checkInternalName (
704     final String JavaDoc name,
705     final int start,
706     final int end,
707     final String JavaDoc msg)
708   {
709     if (name == null || name.length() == 0) {
710       throw new IllegalArgumentException JavaDoc(
711         "Invalid " + msg + " (must not be null or empty)");
712     }
713     int max = (end == -1 ? name.length() : end);
714     try {
715       int begin = start;
716       int slash;
717       do {
718         slash = name.indexOf('/', begin + 1);
719         if (slash == -1 || slash > max) {
720           slash = max;
721         }
722         checkIdentifier(name, begin, slash, null);
723         begin = slash + 1;
724       } while (slash != max);
725     } catch (IllegalArgumentException JavaDoc _) {
726       throw new IllegalArgumentException JavaDoc(
727         "Invalid " + msg +
728         " (must be a fully qualified class name in internal form): " +
729         name);
730     }
731   }
732
733   /**
734    * Checks that the given string is a valid type descriptor.
735    *
736    * @param desc the string to be checked.
737    * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
738    */

739
740   static void checkDesc (final String JavaDoc desc, final boolean canBeVoid) {
741     int end = checkDesc(desc, 0, canBeVoid);
742     if (end != desc.length()) {
743       throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
744     }
745   }
746
747   /**
748    * Checks that a the given substring is a valid type descriptor.
749    *
750    * @param desc the string to be checked.
751    * @param start index of the first character of the identifier (inclusive).
752    * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
753    * @return the index of the last character of the type decriptor, plus one.
754    */

755
756   static int checkDesc (
757     final String JavaDoc desc,
758     final int start,
759     final boolean canBeVoid)
760   {
761     if (desc == null || start >= desc.length()) {
762       throw new IllegalArgumentException JavaDoc(
763         "Invalid type descriptor (must not be null or empty)");
764     }
765     int index;
766     switch (desc.charAt(start)) {
767       case 'V':
768         if (canBeVoid) {
769           return start + 1;
770         } else {
771           throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
772         }
773       case 'Z':
774       case 'C':
775       case 'B':
776       case 'S':
777       case 'I':
778       case 'F':
779       case 'J':
780       case 'D':
781         return start + 1;
782       case '[':
783         index = start + 1;
784         while (index < desc.length() && desc.charAt(index) == '[') {
785           ++index;
786         }
787         if (index < desc.length()) {
788           return checkDesc(desc, index, false);
789         } else {
790           throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
791         }
792       case 'L':
793         index = desc.indexOf(';', start);
794         if (index == -1 || index - start < 2) {
795           throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
796         }
797         try {
798           checkInternalName(desc, start + 1, index, null);
799         } catch (IllegalArgumentException JavaDoc _) {
800           throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
801         }
802         return index + 1;
803       default:
804         throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
805     }
806   }
807
808   /**
809    * Checks that the given string is a valid method descriptor.
810    *
811    * @param desc the string to be checked.
812    */

813
814   static void checkMethodDesc (final String JavaDoc desc) {
815     if (desc == null || desc.length() == 0) {
816       throw new IllegalArgumentException JavaDoc(
817         "Invalid method descriptor (must not be null or empty)");
818     }
819     if (desc.charAt(0) != '(' || desc.length() < 3) {
820       throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
821     }
822     int start = 1;
823     if (desc.charAt(start) != ')') {
824       do {
825         if (desc.charAt(start) == 'V') {
826           throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
827         }
828         start = checkDesc(desc, start, false);
829       } while (start < desc.length() && desc.charAt(start) != ')');
830     }
831     start = checkDesc(desc, start + 1, true);
832     if (start != desc.length()) {
833       throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
834     }
835   }
836
837   /**
838    * Checks that the given label is not null. This method can also check that
839    * the label has been visited.
840    *
841    * @param label the label to be checked.
842    * @param checkVisited <tt>true</tt> to check that the label has been visited.
843    * @param msg a message to be used in case of error.
844    */

845
846   void checkLabel (
847     final Label label,
848     final boolean checkVisited,
849     final String JavaDoc msg)
850   {
851     if (label == null) {
852       throw new IllegalArgumentException JavaDoc(
853         "Invalid " + msg + " (must not be null)");
854     }
855     if (checkVisited && labels.get(label) == null) {
856       throw new IllegalArgumentException JavaDoc(
857         "Invalid " + msg + " (must be visited first)");
858     }
859   }
860 }
861
Popular Tags