KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.io.FileInputStream JavaDoc;
33 import java.util.List JavaDoc;
34
35 import org.objectweb.asm.AnnotationVisitor;
36 import org.objectweb.asm.FieldVisitor;
37 import org.objectweb.asm.ClassAdapter;
38 import org.objectweb.asm.ClassReader;
39 import org.objectweb.asm.ClassVisitor;
40 import org.objectweb.asm.MethodVisitor;
41 import org.objectweb.asm.Opcodes;
42 import org.objectweb.asm.Attribute;
43 import org.objectweb.asm.Type;
44 import org.objectweb.asm.tree.AbstractInsnNode;
45 import org.objectweb.asm.tree.MethodNode;
46 import org.objectweb.asm.tree.ClassNode;
47 import org.objectweb.asm.tree.analysis.Analyzer;
48 import org.objectweb.asm.tree.analysis.SimpleVerifier;
49 import org.objectweb.asm.tree.analysis.Frame;
50
51 /**
52  * A {@link ClassAdapter} that checks that its methods are properly used. More
53  * precisely this class adapter checks each method call individually, based
54  * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i>
55  * of method calls. For example, the invalid sequence
56  * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC,
57  * "i", "D", null)</tt>
58  * will <i>not</i> be detected by this class adapter.
59  *
60  * @author Eric Bruneton
61  */

62 public class CheckClassAdapter extends ClassAdapter {
63
64     /**
65      * <tt>true</tt> if the visit method has been called.
66      */

67     private boolean start;
68
69     /**
70      * <tt>true</tt> if the visitEnd method has been called.
71      */

72     private boolean end;
73
74     /**
75      * Checks a given class. <p> Usage: CheckClassAdapter &lt;fully qualified
76      * class name or class file name&gt;
77      *
78      * @param args the command line arguments.
79      *
80      * @throws Exception if the class cannot be found, or if an IO exception
81      * occurs.
82      */

83     public static void main(final String JavaDoc[] args) throws Exception JavaDoc {
84         if (args.length != 1) {
85             System.err.println("Verifies the given class.");
86             System.err.println("Usage: CheckClassAdapter "
87                     + "<fully qualified class name or class file name>");
88             System.exit(-1);
89         }
90         ClassReader cr;
91         if (args[0].endsWith(".class")) {
92             cr = new ClassReader(new FileInputStream JavaDoc(args[0]));
93         } else {
94             cr = new ClassReader(args[0]);
95         }
96
97         ClassNode cn = new ClassNode();
98         cr.accept(new CheckClassAdapter(cn), true);
99
100         List JavaDoc methods = cn.methods;
101         for (int i = 0; i < methods.size(); ++i) {
102             MethodNode method = (MethodNode) methods.get(i);
103             if (method.instructions.size() > 0) {
104                 Analyzer a = new Analyzer(new SimpleVerifier(Type.getType("L"
105                         + cn.name + ";"),
106                         Type.getType("L" + cn.superName + ";"),
107                         (cn.access & Opcodes.ACC_INTERFACE) != 0));
108                 try {
109                     a.analyze(cn.name, method);
110                     continue;
111                 } catch (Exception JavaDoc e) {
112                     e.printStackTrace();
113                 }
114                 final Frame[] frames = a.getFrames();
115
116                 System.out.println(method.name + method.desc);
117                 TraceMethodVisitor mv = new TraceMethodVisitor() {
118                     public void visitMaxs(
119                         final int maxStack,
120                         final int maxLocals)
121                     {
122                         for (int i = 0; i < text.size(); ++i) {
123                             String JavaDoc s = frames[i] == null
124                                     ? "null"
125                                     : frames[i].toString();
126                             while (s.length() < maxStack + maxLocals + 1) {
127                                 s += " ";
128                             }
129                             System.out.print(Integer.toString(i + 100000)
130                                     .substring(1));
131                             System.out.print(" " + s + " : " + text.get(i));
132                         }
133                         System.out.println();
134                     }
135                 };
136                 for (int j = 0; j < method.instructions.size(); ++j) {
137                     ((AbstractInsnNode) method.instructions.get(j)).accept(mv);
138                 }
139                 mv.visitMaxs(method.maxStack, method.maxLocals);
140             }
141         }
142     }
143
144     /**
145      * Constructs a new {@link CheckClassAdapter}.
146      *
147      * @param cv the class visitor to which this adapter must delegate calls.
148      */

149     public CheckClassAdapter(final ClassVisitor cv) {
150         super(cv);
151     }
152
153     // ------------------------------------------------------------------------
154
// Implementation of the ClassVisitor interface
155
// ------------------------------------------------------------------------
156

157     public void visit(
158         final int version,
159         final int access,
160         final String JavaDoc name,
161         final String JavaDoc signature,
162         final String JavaDoc superName,
163         final String JavaDoc[] interfaces)
164     {
165         if (start) {
166             throw new IllegalStateException JavaDoc("visit must be called only once");
167         } else {
168             start = true;
169         }
170         checkState();
171         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
172                 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
173                 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
174                 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
175                 + Opcodes.ACC_DEPRECATED);
176         CheckMethodAdapter.checkInternalName(name, "class name");
177         if (name.equals("java/lang/Object")) {
178             if (superName != null) {
179                 throw new IllegalArgumentException JavaDoc("The super class name of the Object class must be 'null'");
180             }
181         } else {
182             CheckMethodAdapter.checkInternalName(superName, "super class name");
183         }
184         if (signature != null) {
185             // TODO
186
}
187         if ((access & Opcodes.ACC_INTERFACE) != 0) {
188             if (!superName.equals("java/lang/Object")) {
189                 throw new IllegalArgumentException JavaDoc("The super class name of interfaces must be 'java/lang/Object'");
190             }
191         }
192         if (interfaces != null) {
193             for (int i = 0; i < interfaces.length; ++i) {
194                 CheckMethodAdapter.checkInternalName(interfaces[i],
195                         "interface name at index " + i);
196             }
197         }
198         cv.visit(version, access, name, signature, superName, interfaces);
199     }
200
201     public void visitSource(final String JavaDoc file, final String JavaDoc debug) {
202         // TODO check called only once, after visit()
203
cv.visitSource(file, debug);
204     }
205
206     public void visitOuterClass(
207         final String JavaDoc owner,
208         final String JavaDoc name,
209         final String JavaDoc desc)
210     {
211         // TODO check called only once, after visit(); check arguments
212
cv.visitOuterClass(owner, name, desc);
213     }
214
215     public void visitInnerClass(
216         final String JavaDoc name,
217         final String JavaDoc outerName,
218         final String JavaDoc innerName,
219         final int access)
220     {
221         checkState();
222         CheckMethodAdapter.checkInternalName(name, "class name");
223         if (outerName != null) {
224             CheckMethodAdapter.checkInternalName(outerName, "outer class name");
225         }
226         if (innerName != null) {
227             CheckMethodAdapter.checkIdentifier(innerName, "inner class name");
228         }
229         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
230                 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
231                 + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE
232                 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
233                 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM);
234         cv.visitInnerClass(name, outerName, innerName, access);
235     }
236
237     public FieldVisitor visitField(
238         final int access,
239         final String JavaDoc name,
240         final String JavaDoc desc,
241         final String JavaDoc signature,
242         final Object JavaDoc value)
243     {
244         checkState();
245         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
246                 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
247                 + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE
248                 + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC
249                 + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED);
250         CheckMethodAdapter.checkIdentifier(name, "field name");
251         CheckMethodAdapter.checkDesc(desc, false);
252         if (signature != null) {
253             // TODO
254
}
255         if (value != null) {
256             CheckMethodAdapter.checkConstant(value);
257         }
258         FieldVisitor av = cv.visitField(access, name, desc, signature, value);
259         // TODO return checkadapter(av)
260
return av;
261     }
262
263     public MethodVisitor visitMethod(
264         final int access,
265         final String JavaDoc name,
266         final String JavaDoc desc,
267         final String JavaDoc signature,
268         final String JavaDoc[] exceptions)
269     {
270         checkState();
271         checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
272                 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
273                 + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED
274                 + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE
275                 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT
276                 + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED);
277         CheckMethodAdapter.checkMethodIdentifier(name, "method name");
278         CheckMethodAdapter.checkMethodDesc(desc);
279         if (signature != null) {
280             // TODO
281
}
282         if (exceptions != null) {
283             for (int i = 0; i < exceptions.length; ++i) {
284                 CheckMethodAdapter.checkInternalName(exceptions[i],
285                         "exception name at index " + i);
286             }
287         }
288         return new CheckMethodAdapter(cv.visitMethod(access,
289                 name,
290                 desc,
291                 signature,
292                 exceptions));
293     }
294
295     public AnnotationVisitor visitAnnotation(
296         final String JavaDoc desc,
297         final boolean visible)
298     {
299         // TODO
300
return cv.visitAnnotation(desc, visible);
301     }
302
303     public void visitAttribute(final Attribute attr) {
304         checkState();
305         if (attr == null) {
306             throw new IllegalArgumentException JavaDoc("Invalid attribute (must not be null)");
307         }
308     }
309
310     public void visitEnd() {
311         checkState();
312         end = true;
313         cv.visitEnd();
314     }
315
316     // ------------------------------------------------------------------------
317
// Utility methods
318
// ------------------------------------------------------------------------
319

320     /**
321      * Checks that the visit method has been called and that visitEnd has not
322      * been called.
323      */

324     private void checkState() {
325         if (!start) {
326             throw new IllegalStateException JavaDoc("Cannot visit member before visit has been called.");
327         }
328         if (end) {
329             throw new IllegalStateException JavaDoc("Cannot visit member after visitEnd has been called.");
330         }
331     }
332
333     /**
334      * Checks that the given access flags do not contain invalid flags. This
335      * method also checks that mutually incompatible flags are not set
336      * simultaneously.
337      *
338      * @param access the access flags to be checked
339      * @param possibleAccess the valid access flags.
340      */

341     static void checkAccess(final int access, final int possibleAccess) {
342         if ((access & ~possibleAccess) != 0) {
343             throw new IllegalArgumentException JavaDoc("Invalid access flags: "
344                     + access);
345         }
346         int pub = ((access & Opcodes.ACC_PUBLIC) != 0 ? 1 : 0);
347         int pri = ((access & Opcodes.ACC_PRIVATE) != 0 ? 1 : 0);
348         int pro = ((access & Opcodes.ACC_PROTECTED) != 0 ? 1 : 0);
349         if (pub + pri + pro > 1) {
350             throw new IllegalArgumentException JavaDoc("public private and protected are mutually exclusive: "
351                     + access);
352         }
353         int fin = ((access & Opcodes.ACC_FINAL) != 0 ? 1 : 0);
354         int abs = ((access & Opcodes.ACC_ABSTRACT) != 0 ? 1 : 0);
355         if (fin + abs > 1) {
356             throw new IllegalArgumentException JavaDoc("final and abstract are mutually exclusive: "
357                     + access);
358         }
359     }
360 }
361
Popular Tags