KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > 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  * Contact: Eric.Bruneton@rd.francetelecom.com
31  *
32  * Author: Eric Bruneton
33  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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