KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > asm > util > CheckMethodAdapter


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 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 package org.objectweb.asm.util;
31
32 import org.objectweb.asm.AnnotationVisitor;
33 import org.objectweb.asm.Label;
34 import org.objectweb.asm.MethodAdapter;
35 import org.objectweb.asm.MethodVisitor;
36 import org.objectweb.asm.Opcodes;
37 import org.objectweb.asm.Attribute;
38 import org.objectweb.asm.Type;
39
40 import java.util.HashMap JavaDoc;
41
42 /**
43  * A {@link MethodAdapter} that checks that its methods are properly used. More
44  * precisely this code adapter checks each instruction individually (i.e., each
45  * visit method checks some preconditions based <i>only</i> on its arguments -
46  * such as the fact that the given opcode is correct for a given visit method),
47  * but does <i>not</i> check the <i>sequence</i> of instructions. For example,
48  * in a method whose signature is <tt>void m ()</tt>, the invalid instruction
49  * IRETURN, or the invalid sequence IADD L2I will <i>not</i> be detected by
50  * this code adapter.
51  *
52  * @author Eric Bruneton
53  */

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

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

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

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

295     /**
296      * Constructs a new {@link CheckMethodAdapter} object.
297      *
298      * @param cv the code visitor to which this adapter must delegate calls.
299      */

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

560     /**
561      * Checks that the visitMaxs method has not been called.
562      */

563     void checkEnd() {
564         if (end) {
565             throw new IllegalStateException JavaDoc("Cannot visit instructions after visitMaxs has been called.");
566         }
567     }
568
569     /**
570      * Checks that the type of the given opcode is equal to the given type.
571      *
572      * @param opcode the opcode to be checked.
573      * @param type the expected opcode type.
574      */

575     static void checkOpcode(final int opcode, final int type) {
576         if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
577             throw new IllegalArgumentException JavaDoc("Invalid opcode: " + opcode);
578         }
579     }
580
581     /**
582      * Checks that the given value is a signed byte.
583      *
584      * @param value the value to be checked.
585      * @param msg an message to be used in case of error.
586      */

587     static void checkSignedByte(final int value, final String JavaDoc msg) {
588         if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
589             throw new IllegalArgumentException JavaDoc(msg
590                     + " (must be a signed byte): " + value);
591         }
592     }
593
594     /**
595      * Checks that the given value is a signed short.
596      *
597      * @param value the value to be checked.
598      * @param msg an message to be used in case of error.
599      */

600     static void checkSignedShort(final int value, final String JavaDoc msg) {
601         if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
602             throw new IllegalArgumentException JavaDoc(msg
603                     + " (must be a signed short): " + value);
604         }
605     }
606
607     /**
608      * Checks that the given value is an unsigned short.
609      *
610      * @param value the value to be checked.
611      * @param msg an message to be used in case of error.
612      */

613     static void checkUnsignedShort(final int value, final String JavaDoc msg) {
614         if (value < 0 || value > 65535) {
615             throw new IllegalArgumentException JavaDoc(msg
616                     + " (must be an unsigned short): " + value);
617         }
618     }
619
620     /**
621      * Checks that the given value is an {@link Integer}, a{@link Float}, a
622      * {@link Long}, a {@link Double} or a {@link String}.
623      *
624      * @param cst the value to be checked.
625      */

626     static void checkConstant(final Object JavaDoc cst) {
627         if (!(cst instanceof Integer JavaDoc) && !(cst instanceof Float JavaDoc)
628                 && !(cst instanceof Long JavaDoc) && !(cst instanceof Double JavaDoc)
629                 && !(cst instanceof String JavaDoc))
630         {
631             throw new IllegalArgumentException JavaDoc("Invalid constant: " + cst);
632         }
633     }
634
635     /**
636      * Checks that the given string is a valid Java identifier.
637      *
638      * @param name the string to be checked.
639      * @param msg a message to be used in case of error.
640      */

641     static void checkIdentifier(final String JavaDoc name, final String JavaDoc msg) {
642         checkIdentifier(name, 0, -1, msg);
643     }
644
645     /**
646      * Checks that the given substring is a valid Java identifier.
647      *
648      * @param name the string to be checked.
649      * @param start index of the first character of the identifier (inclusive).
650      * @param end index of the last character of the identifier (exclusive). -1
651      * is equivalent to <tt>name.length()</tt> if name is not
652      * <tt>null</tt>.
653      * @param msg a message to be used in case of error.
654      */

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

686     static void checkMethodIdentifier(final String JavaDoc name, final String JavaDoc msg) {
687         if (name == null || name.length() == 0) {
688             throw new IllegalArgumentException JavaDoc("Invalid " + msg
689                     + " (must not be null or empty)");
690         }
691         if (name.equals("<init>") || name.equals("<clinit>")) {
692             return;
693         }
694         if (!Character.isJavaIdentifierStart(name.charAt(0))) {
695             throw new IllegalArgumentException JavaDoc("Invalid "
696                     + msg
697                     + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
698                     + name);
699         }
700         for (int i = 1; i < name.length(); ++i) {
701             if (!Character.isJavaIdentifierPart(name.charAt(i))) {
702                 throw new IllegalArgumentException JavaDoc("Invalid "
703                         + msg
704                         + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
705                         + name);
706             }
707         }
708     }
709
710     /**
711      * Checks that the given string is a valid internal class name.
712      *
713      * @param name the string to be checked.
714      * @param msg a message to be used in case of error.
715      */

716     static void checkInternalName(final String JavaDoc name, final String JavaDoc msg) {
717         checkInternalName(name, 0, -1, msg);
718     }
719
720     /**
721      * Checks that the given substring is a valid internal class name.
722      *
723      * @param name the string to be checked.
724      * @param start index of the first character of the identifier (inclusive).
725      * @param end index of the last character of the identifier (exclusive). -1
726      * is equivalent to <tt>name.length()</tt> if name is not
727      * <tt>null</tt>.
728      * @param msg a message to be used in case of error.
729      */

730     static void checkInternalName(
731         final String JavaDoc name,
732         final int start,
733         final int end,
734         final String JavaDoc msg)
735     {
736         if (name == null || name.length() == 0) {
737             throw new IllegalArgumentException JavaDoc("Invalid " + msg
738                     + " (must not be null or empty)");
739         }
740         int max = (end == -1 ? name.length() : end);
741         try {
742             int begin = start;
743             int slash;
744             do {
745                 slash = name.indexOf('/', begin + 1);
746                 if (slash == -1 || slash > max) {
747                     slash = max;
748                 }
749                 checkIdentifier(name, begin, slash, null);
750                 begin = slash + 1;
751             } while (slash != max);
752         } catch (IllegalArgumentException JavaDoc _) {
753             throw new IllegalArgumentException JavaDoc("Invalid "
754                     + msg
755                     + " (must be a fully qualified class name in internal form): "
756                     + name);
757         }
758     }
759
760     /**
761      * Checks that the given string is a valid type descriptor.
762      *
763      * @param desc the string to be checked.
764      * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
765      */

766     static void checkDesc(final String JavaDoc desc, final boolean canBeVoid) {
767         int end = checkDesc(desc, 0, canBeVoid);
768         if (end != desc.length()) {
769             throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
770         }
771     }
772
773     /**
774      * Checks that a the given substring is a valid type descriptor.
775      *
776      * @param desc the string to be checked.
777      * @param start index of the first character of the identifier (inclusive).
778      * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
779      * @return the index of the last character of the type decriptor, plus one.
780      */

781     static int checkDesc(
782         final String JavaDoc desc,
783         final int start,
784         final boolean canBeVoid)
785     {
786         if (desc == null || start >= desc.length()) {
787             throw new IllegalArgumentException JavaDoc("Invalid type descriptor (must not be null or empty)");
788         }
789         int index;
790         switch (desc.charAt(start)) {
791             case 'V':
792                 if (canBeVoid) {
793                     return start + 1;
794                 } else {
795                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
796                             + desc);
797                 }
798             case 'Z':
799             case 'C':
800             case 'B':
801             case 'S':
802             case 'I':
803             case 'F':
804             case 'J':
805             case 'D':
806                 return start + 1;
807             case '[':
808                 index = start + 1;
809                 while (index < desc.length() && desc.charAt(index) == '[') {
810                     ++index;
811                 }
812                 if (index < desc.length()) {
813                     return checkDesc(desc, index, false);
814                 } else {
815                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
816                             + desc);
817                 }
818             case 'L':
819                 index = desc.indexOf(';', start);
820                 if (index == -1 || index - start < 2) {
821                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
822                             + desc);
823                 }
824                 try {
825                     checkInternalName(desc, start + 1, index, null);
826                 } catch (IllegalArgumentException JavaDoc _) {
827                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
828                             + desc);
829                 }
830                 return index + 1;
831             default:
832                 throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
833                         + desc);
834         }
835     }
836
837     /**
838      * Checks that the given string is a valid method descriptor.
839      *
840      * @param desc the string to be checked.
841      */

842     static void checkMethodDesc(final String JavaDoc desc) {
843         if (desc == null || desc.length() == 0) {
844             throw new IllegalArgumentException JavaDoc("Invalid method descriptor (must not be null or empty)");
845         }
846         if (desc.charAt(0) != '(' || desc.length() < 3) {
847             throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
848         }
849         int start = 1;
850         if (desc.charAt(start) != ')') {
851             do {
852                 if (desc.charAt(start) == 'V') {
853                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
854                             + desc);
855                 }
856                 start = checkDesc(desc, start, false);
857             } while (start < desc.length() && desc.charAt(start) != ')');
858         }
859         start = checkDesc(desc, start + 1, true);
860         if (start != desc.length()) {
861             throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
862         }
863     }
864
865     /**
866      * Checks that the given label is not null. This method can also check that
867      * the label has been visited.
868      *
869      * @param label the label to be checked.
870      * @param checkVisited <tt>true</tt> to check that the label has been
871      * visited.
872      * @param msg a message to be used in case of error.
873      */

874     void checkLabel(
875         final Label label,
876         final boolean checkVisited,
877         final String JavaDoc msg)
878     {
879         if (label == null) {
880             throw new IllegalArgumentException JavaDoc("Invalid " + msg
881                     + " (must not be null)");
882         }
883         if (checkVisited && labels.get(label) == null) {
884             throw new IllegalArgumentException JavaDoc("Invalid " + msg
885                     + " (must be visited first)");
886         }
887     }
888 }
889
Popular Tags