KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > 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 com.tc.asm.util;
31
32 import com.tc.asm.AnnotationVisitor;
33 import com.tc.asm.Label;
34 import com.tc.asm.MethodAdapter;
35 import com.tc.asm.MethodVisitor;
36 import com.tc.asm.Opcodes;
37 import com.tc.asm.Attribute;
38 import com.tc.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 visitCode method has been called.
58      */

59     private boolean startCode;
60
61     /**
62      * <tt>true</tt> if the visitMaxs method has been called.
63      */

64     private boolean endCode;
65
66     /**
67      * <tt>true</tt> if the visitEnd method has been called.
68      */

69     private boolean endMethod;
70
71     /**
72      * The already visited labels. This map associate Integer values to Label
73      * keys.
74      */

75     private HashMap JavaDoc labels;
76
77     /**
78      * Code of the visit method to be used for each opcode.
79      */

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

305     /**
306      * Constructs a new {@link CheckMethodAdapter} object.
307      *
308      * @param cv the code visitor to which this adapter must delegate calls.
309      */

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

596     /**
597      * Checks that the visitCode method has been called.
598      */

599     void checkStartCode() {
600         if (!startCode) {
601             throw new IllegalStateException JavaDoc("Cannot visit instructions before visitCode has been called.");
602         }
603     }
604
605     /**
606      * Checks that the visitMaxs method has not been called.
607      */

608     void checkEndCode() {
609         if (endCode) {
610             throw new IllegalStateException JavaDoc("Cannot visit instructions after visitMaxs has been called.");
611         }
612     }
613
614     /**
615      * Checks that the visitEnd method has not been called.
616      */

617     void checkEndMethod() {
618         if (endMethod) {
619             throw new IllegalStateException JavaDoc("Cannot visit elements after visitEnd has been called.");
620         }
621     }
622
623     /**
624      * Checks that the type of the given opcode is equal to the given type.
625      *
626      * @param opcode the opcode to be checked.
627      * @param type the expected opcode type.
628      */

629     static void checkOpcode(final int opcode, final int type) {
630         if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
631             throw new IllegalArgumentException JavaDoc("Invalid opcode: " + opcode);
632         }
633     }
634
635     /**
636      * Checks that the given value is a signed byte.
637      *
638      * @param value the value to be checked.
639      * @param msg an message to be used in case of error.
640      */

641     static void checkSignedByte(final int value, final String JavaDoc msg) {
642         if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
643             throw new IllegalArgumentException JavaDoc(msg
644                     + " (must be a signed byte): " + value);
645         }
646     }
647
648     /**
649      * Checks that the given value is a signed short.
650      *
651      * @param value the value to be checked.
652      * @param msg an message to be used in case of error.
653      */

654     static void checkSignedShort(final int value, final String JavaDoc msg) {
655         if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
656             throw new IllegalArgumentException JavaDoc(msg
657                     + " (must be a signed short): " + value);
658         }
659     }
660
661     /**
662      * Checks that the given value is an unsigned short.
663      *
664      * @param value the value to be checked.
665      * @param msg an message to be used in case of error.
666      */

667     static void checkUnsignedShort(final int value, final String JavaDoc msg) {
668         if (value < 0 || value > 65535) {
669             throw new IllegalArgumentException JavaDoc(msg
670                     + " (must be an unsigned short): " + value);
671         }
672     }
673
674     /**
675      * Checks that the given value is an {@link Integer}, a{@link Float}, a
676      * {@link Long}, a {@link Double} or a {@link String}.
677      *
678      * @param cst the value to be checked.
679      */

680     static void checkConstant(final Object JavaDoc cst) {
681         if (!(cst instanceof Integer JavaDoc) && !(cst instanceof Float JavaDoc)
682                 && !(cst instanceof Long JavaDoc) && !(cst instanceof Double JavaDoc)
683                 && !(cst instanceof String JavaDoc))
684         {
685             throw new IllegalArgumentException JavaDoc("Invalid constant: " + cst);
686         }
687     }
688
689     /**
690      * Checks that the given string is a valid Java identifier.
691      *
692      * @param name the string to be checked.
693      * @param msg a message to be used in case of error.
694      */

695     static void checkIdentifier(final String JavaDoc name, final String JavaDoc msg) {
696         checkIdentifier(name, 0, -1, msg);
697     }
698
699     /**
700      * Checks that the given substring is a valid Java identifier.
701      *
702      * @param name the string to be checked.
703      * @param start index of the first character of the identifier (inclusive).
704      * @param end index of the last character of the identifier (exclusive). -1
705      * is equivalent to <tt>name.length()</tt> if name is not
706      * <tt>null</tt>.
707      * @param msg a message to be used in case of error.
708      */

709     static void checkIdentifier(
710         final String JavaDoc name,
711         final int start,
712         final int end,
713         final String JavaDoc msg)
714     {
715         if (name == null || (end == -1 ? name.length() <= start : end <= start))
716         {
717             throw new IllegalArgumentException JavaDoc("Invalid " + msg
718                     + " (must not be null or empty)");
719         }
720         if (!Character.isJavaIdentifierStart(name.charAt(start))) {
721             throw new IllegalArgumentException JavaDoc("Invalid " + msg
722                     + " (must be a valid Java identifier): " + name);
723         }
724         int max = (end == -1 ? name.length() : end);
725         for (int i = start + 1; i < max; ++i) {
726             if (!Character.isJavaIdentifierPart(name.charAt(i))) {
727                 throw new IllegalArgumentException JavaDoc("Invalid " + msg
728                         + " (must be a valid Java identifier): " + name);
729             }
730         }
731     }
732
733     /**
734      * Checks that the given string is a valid Java identifier or is equal to
735      * '&lt;init&gt;' or '&lt;clinit&gt;'.
736      *
737      * @param name the string to be checked.
738      * @param msg a message to be used in case of error.
739      */

740     static void checkMethodIdentifier(final String JavaDoc name, final String JavaDoc msg) {
741         if (name == null || name.length() == 0) {
742             throw new IllegalArgumentException JavaDoc("Invalid " + msg
743                     + " (must not be null or empty)");
744         }
745         if (name.equals("<init>") || name.equals("<clinit>")) {
746             return;
747         }
748         if (!Character.isJavaIdentifierStart(name.charAt(0))) {
749             throw new IllegalArgumentException JavaDoc("Invalid "
750                     + msg
751                     + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
752                     + name);
753         }
754         for (int i = 1; i < name.length(); ++i) {
755             if (!Character.isJavaIdentifierPart(name.charAt(i))) {
756                 throw new IllegalArgumentException JavaDoc("Invalid "
757                         + msg
758                         + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
759                         + name);
760             }
761         }
762     }
763
764     /**
765      * Checks that the given string is a valid internal class name.
766      *
767      * @param name the string to be checked.
768      * @param msg a message to be used in case of error.
769      */

770     static void checkInternalName(final String JavaDoc name, final String JavaDoc msg) {
771         checkInternalName(name, 0, -1, msg);
772     }
773
774     /**
775      * Checks that the given substring is a valid internal class name.
776      *
777      * @param name the string to be checked.
778      * @param start index of the first character of the identifier (inclusive).
779      * @param end index of the last character of the identifier (exclusive). -1
780      * is equivalent to <tt>name.length()</tt> if name is not
781      * <tt>null</tt>.
782      * @param msg a message to be used in case of error.
783      */

784     static void checkInternalName(
785         final String JavaDoc name,
786         final int start,
787         final int end,
788         final String JavaDoc msg)
789     {
790         if (name == null || name.length() == 0) {
791             throw new IllegalArgumentException JavaDoc("Invalid " + msg
792                     + " (must not be null or empty)");
793         }
794         int max = (end == -1 ? name.length() : end);
795         try {
796             int begin = start;
797             int slash;
798             do {
799                 slash = name.indexOf('/', begin + 1);
800                 if (slash == -1 || slash > max) {
801                     slash = max;
802                 }
803                 checkIdentifier(name, begin, slash, null);
804                 begin = slash + 1;
805             } while (slash != max);
806         } catch (IllegalArgumentException JavaDoc _) {
807             throw new IllegalArgumentException JavaDoc("Invalid "
808                     + msg
809                     + " (must be a fully qualified class name in internal form): "
810                     + name);
811         }
812     }
813
814     /**
815      * Checks that the given string is a valid type descriptor.
816      *
817      * @param desc the string to be checked.
818      * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
819      */

820     static void checkDesc(final String JavaDoc desc, final boolean canBeVoid) {
821         int end = checkDesc(desc, 0, canBeVoid);
822         if (end != desc.length()) {
823             throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
824         }
825     }
826
827     /**
828      * Checks that a the given substring is a valid type descriptor.
829      *
830      * @param desc the string to be checked.
831      * @param start index of the first character of the identifier (inclusive).
832      * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
833      * @return the index of the last character of the type decriptor, plus one.
834      */

835     static int checkDesc(
836         final String JavaDoc desc,
837         final int start,
838         final boolean canBeVoid)
839     {
840         if (desc == null || start >= desc.length()) {
841             throw new IllegalArgumentException JavaDoc("Invalid type descriptor (must not be null or empty)");
842         }
843         int index;
844         switch (desc.charAt(start)) {
845             case 'V':
846                 if (canBeVoid) {
847                     return start + 1;
848                 } else {
849                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
850                             + desc);
851                 }
852             case 'Z':
853             case 'C':
854             case 'B':
855             case 'S':
856             case 'I':
857             case 'F':
858             case 'J':
859             case 'D':
860                 return start + 1;
861             case '[':
862                 index = start + 1;
863                 while (index < desc.length() && desc.charAt(index) == '[') {
864                     ++index;
865                 }
866                 if (index < desc.length()) {
867                     return checkDesc(desc, index, false);
868                 } else {
869                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
870                             + desc);
871                 }
872             case 'L':
873                 index = desc.indexOf(';', start);
874                 if (index == -1 || index - start < 2) {
875                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
876                             + desc);
877                 }
878                 try {
879                     checkInternalName(desc, start + 1, index, null);
880                 } catch (IllegalArgumentException JavaDoc _) {
881                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
882                             + desc);
883                 }
884                 return index + 1;
885             default:
886                 throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
887                         + desc);
888         }
889     }
890
891     /**
892      * Checks that the given string is a valid method descriptor.
893      *
894      * @param desc the string to be checked.
895      */

896     static void checkMethodDesc(final String JavaDoc desc) {
897         if (desc == null || desc.length() == 0) {
898             throw new IllegalArgumentException JavaDoc("Invalid method descriptor (must not be null or empty)");
899         }
900         if (desc.charAt(0) != '(' || desc.length() < 3) {
901             throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
902         }
903         int start = 1;
904         if (desc.charAt(start) != ')') {
905             do {
906                 if (desc.charAt(start) == 'V') {
907                     throw new IllegalArgumentException JavaDoc("Invalid descriptor: "
908                             + desc);
909                 }
910                 start = checkDesc(desc, start, false);
911             } while (start < desc.length() && desc.charAt(start) != ')');
912         }
913         start = checkDesc(desc, start + 1, true);
914         if (start != desc.length()) {
915             throw new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
916         }
917     }
918
919     /**
920      * Checks that the given label is not null. This method can also check that
921      * the label has been visited.
922      *
923      * @param label the label to be checked.
924      * @param checkVisited <tt>true</tt> to check that the label has been
925      * visited.
926      * @param msg a message to be used in case of error.
927      */

928     void checkLabel(
929         final Label label,
930         final boolean checkVisited,
931         final String JavaDoc msg)
932     {
933         if (label == null) {
934             throw new IllegalArgumentException JavaDoc("Invalid " + msg
935                     + " (must not be null)");
936         }
937         if (checkVisited && labels.get(label) == null) {
938             throw new IllegalArgumentException JavaDoc("Invalid " + msg
939                     + " (must be visited first)");
940         }
941     }
942 }
943
Popular Tags