KickJava   Java API By Example, From Geeks To Geeks.

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


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

30
31 package oracle.toplink.libraries.asm.util;
32
33 import java.io.FileInputStream JavaDoc;
34 import java.util.List JavaDoc;
35
36 import oracle.toplink.libraries.asm.ClassAdapter;
37 import oracle.toplink.libraries.asm.ClassReader;
38 import oracle.toplink.libraries.asm.ClassVisitor;
39 import oracle.toplink.libraries.asm.CodeVisitor;
40 import oracle.toplink.libraries.asm.Constants;
41 import oracle.toplink.libraries.asm.Attribute;
42 import oracle.toplink.libraries.asm.Label;
43 import oracle.toplink.libraries.asm.tree.AbstractInsnNode;
44 import oracle.toplink.libraries.asm.tree.MethodNode;
45 import oracle.toplink.libraries.asm.tree.TreeClassAdapter;
46 import oracle.toplink.libraries.asm.tree.analysis.Analyzer;
47 import oracle.toplink.libraries.asm.tree.analysis.SimpleVerifier;
48 import oracle.toplink.libraries.asm.tree.analysis.Frame;
49
50 /**
51  * A {@link ClassAdapter ClassAdapter} that checks that its methods are properly
52  * used. More precisely this class adapter checks each method call individually,
53  * based <i>only</i> on its arguments, but does <i>not</i> check the
54  * <i>sequence</i> of method calls. For example, the invalid sequence
55  * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC,
56  * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter.
57  *
58  * @author Eric Bruneton
59  */

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

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

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

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

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

316   /**
317    * Checks that the visit method has been called and that visitEnd has not been
318    * called.
319    */

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

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