View Javadoc
1   package org.apache.river.tool.classdepend;
2   
3   /***
4    * ASM examples: examples showing how ASM can be used
5    * Copyright (c) 2000-2005 INRIA, France Telecom
6    * All rights reserved.
7    *
8    * Redistribution and use in source and binary forms, with or without
9    * modification, are permitted provided that the following conditions
10   * are met:
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer.
13   * 2. Redistributions in binary form must reproduce the above copyright
14   *    notice, this list of conditions and the following disclaimer in the
15   *    documentation and/or other materials provided with the distribution.
16   * 3. Neither the name of the copyright holders nor the names of its
17   *    contributors may be used to endorse or promote products derived from
18   *    this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30   * THE POSSIBILITY OF SUCH DAMAGE.
31   */
32  
33  import java.util.regex.Matcher;
34  import java.util.regex.Pattern;
35  import org.objectweb.asm.AnnotationVisitor;
36  import org.objectweb.asm.ClassVisitor;
37  import org.objectweb.asm.FieldVisitor;
38  import org.objectweb.asm.Label;
39  import org.objectweb.asm.MethodVisitor;
40  import org.objectweb.asm.Opcodes;
41  import org.objectweb.asm.Type;
42  import org.objectweb.asm.signature.SignatureReader;
43  import org.objectweb.asm.signature.SignatureVisitor;
44  
45  /**
46   * 
47   * 
48   */
49  abstract class AbstractDependencyVisitor extends ClassVisitor {
50  
51      AbstractDependencyVisitor() {
52          super(Opcodes.ASM5);
53      }
54  
55      abstract protected void addName(String name);
56  
57      /* -- ClassVisitor -- */
58  
59      @Override
60      public void visit(int version, int access, String name, String signature,
61  		      String superName, String[] interfaces)
62      {
63  	if (signature == null) {
64  	    addNameInternal(superName, false);
65  	    addNames(interfaces);
66  	} else {
67  	    addSignature(signature);
68  	}
69          super.visit(version, access, name, signature, superName, interfaces);
70      }
71      
72      @Override
73      public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
74  	addDesc(desc);
75  	AnnotationVisitor ann = super.visitAnnotation(desc, visible);
76          if (ann != null) return new AnnotationVisit(Opcodes.ASM5, ann);
77          return null;
78      }
79  
80      @Override
81      public FieldVisitor visitField(int access, String name, String desc,
82  				   String signature, Object value)
83      {
84  	if (signature == null) {
85  	    addDesc(desc);
86  	} else {
87  	    addTypeSignature(signature);
88  	}
89  	if (value instanceof Type) {
90              addType((Type) value);
91          }
92  	return super.visitField(access, name, desc, signature, value);
93      }
94      
95      @Override
96      public MethodVisitor visitMethod(int access, String name, String desc,
97  				     String signature, String[] exceptions)
98      {
99          if (signature == null) {
100             addMethodDesc(desc);
101         } else {
102             addSignature(signature);
103         }
104         addNames(exceptions);
105         return new MethodVisit(Opcodes.ASM5, super.visitMethod(api, desc, desc, desc, exceptions));
106     }
107 
108     @Override
109     public void visitInnerClass(String name, String outerName,
110 				String innerName, int access)
111     {
112 	/* XXX: Do we need to consider inner classes?
113          * Yes the old ClassDep tool includes them */
114         addNameInternal(outerName, false);
115 	addNameInternal(name, false);
116         super.visitInnerClass(name, outerName, innerName, access);
117     }
118 
119    /* -- Utilities -- */
120 
121     private  void addNameInternal(String name, boolean transientField) {
122         if (name != null) {
123 	    addName(name.replace('/', '.'));
124 	}
125     }
126 
127     private void addNames(String[] names) {
128 	if (names != null) {
129             int l = names.length;
130 	    for (int i = 0; i < l; i++) {
131                 String name = names[i];
132 		addNameInternal(name, false);
133 	    }
134 	}
135     }
136 
137     private void addDesc(String desc) {
138         addType(Type.getType(desc));
139     }
140 
141     private void addMethodDesc(String desc) {
142         addType(Type.getReturnType(desc));
143         Type [] type = Type.getArgumentTypes(desc);
144         int l = type.length;
145 	for (int i = 0; i < l; i++) {            
146             addType(type[i]);
147 	}
148     }
149 
150     private void addType(Type t) {
151         switch (t.getSort()) {
152             case Type.ARRAY:
153                 addType(t.getElementType());
154                 break;
155             case Type.OBJECT:
156                 addNameInternal(t.getClassName(), false);
157                 break;
158         }
159     }
160 
161     private void addSignature(String signature) {
162 	new SignatureReader(signature).accept(new SignatureVisit(Opcodes.ASM5));
163     }
164 
165     private void addTypeSignature(String signature) {
166 	new SignatureReader(signature).acceptType(new SignatureVisit(Opcodes.ASM5));
167     }
168     
169     /**
170      * Annotations
171      */
172     private class AnnotationVisit extends AnnotationVisitor {
173 
174         public AnnotationVisit(int i, AnnotationVisitor av) {
175             super(i, av);
176         }
177         
178         @Override
179         public void visit(String name, Object value) {
180             if (value instanceof Type) {
181                 addType((Type) value);
182             }
183             super.visit(name, value);
184         }
185 
186         @Override
187         public void visitEnum(String name, String desc, String value) {
188             addDesc(desc);
189             super.visitEnum(name,desc,value);
190         }
191         
192         @Override
193         public AnnotationVisitor visitAnnotation(String name, String desc) {
194             addDesc(desc);
195             AnnotationVisitor ann = super.visitAnnotation(name, desc);
196             if (ann != null) return new AnnotationVisit( Opcodes.ASM5, ann);
197             return null;
198         }
199         
200     }
201     
202     /**
203      * MethodVisit delegates to encapsulated MethodVisitor as well as
204      * recording dependencies.
205      */
206     private class MethodVisit extends MethodVisitor {
207 
208         public MethodVisit(int i, MethodVisitor mv) {
209             super(i, mv);
210         }
211         
212         @Override
213         public AnnotationVisitor visitParameterAnnotation(int parameter,
214                                                   String desc,
215                                                   boolean visible)
216         {
217             addDesc(desc);
218             AnnotationVisitor ann = super.visitParameterAnnotation(parameter, desc, visible);
219             if (ann != null) return new AnnotationVisit(Opcodes.ASM5, ann );
220             return null;
221         }
222         @Override
223         public void visitTypeInsn(int opcode, String desc) {
224             if (desc.charAt(0) == '[') {
225                 addDesc(desc);
226             } else {
227                 addNameInternal(desc, false);
228             }
229             super.visitTypeInsn(opcode, desc);
230         }
231 
232         @Override
233         public void visitFieldInsn(int opcode, String owner, String name,
234                                    String desc)
235         {
236             addNameInternal(owner, false);
237             addDesc(desc);
238             super.visitFieldInsn(opcode, owner, name, desc);
239         }
240 
241         String pattern = "^\\[{0,2}L{0,1}(\\w+[/.]{1}[\\w$\\d/.]+);{0,1}$";
242         Pattern arrayOfObjects = Pattern.compile(pattern);
243         @Override
244         public void visitMethodInsn(int opcode, String owner, String name,
245                                     String desc, boolean itf)
246         {
247             /* This filters out Generic's and primitive owners.
248              *
249              * Also when the owner is an array, containing Objects and
250              * the method name is clone(), (I think it's got something to do
251              * with cloning array's, this must be a new java 5 language feature
252              * I tested 1.4 code without this ever occurring)      
253              * we can't get the Object's type
254              * using Type.getType(owner) due to the nature of 
255              * the ASM Core API requiring bytecode be read sequentially.
256              * This only occurs with clone() which returns java.lang.Object
257              */
258             Matcher match = arrayOfObjects.matcher(owner);
259             while (match.find()){
260                 String object = match.group(1);
261                 addNameInternal(object, false);
262             } 
263             addMethodDesc(desc);
264             super.visitMethodInsn(opcode, owner, name, desc, itf);
265         }
266 
267         @Override
268         public void visitLdcInsn(Object cst) {
269             if (cst instanceof Type) {
270                 addType((Type) cst);
271             }
272             super.visitLdcInsn(cst);
273         }
274 
275         @Override
276         public void visitMultiANewArrayInsn(String desc, int dims) {
277             addDesc(desc);
278             super.visitMultiANewArrayInsn(desc,dims);
279         }
280 
281         @Override
282         public void visitLocalVariable(String name, String desc, String signature,
283                                        Label start, Label end, int index)
284         {
285             if (signature != null) {
286                 addTypeSignature(signature);
287             }
288             super.visitLocalVariable(name, desc, signature, start, end, index);
289         }
290 
291         @Override
292         public void visitTryCatchBlock(Label start, Label end, Label handler,
293                                        String type)
294         {
295             addNameInternal(type, false);
296             super.visitTryCatchBlock(start, end, handler, type);
297         }
298     }
299     
300     /**
301      * Signatures
302      */
303     private class SignatureVisit extends SignatureVisitor {
304 
305         public SignatureVisit(int i) {
306             super(i);
307         }
308         
309         @Override
310         public void visitTypeVariable(String name) {
311             /* XXX: Need to do something? */
312             //System.out.println(name);
313             super.visitTypeVariable(name);
314         }
315         
316         @Override
317         public void visitClassType(String name) { 
318             addNameInternal(name, false);
319             super.visitClassType(name);
320         }
321         
322         @Override
323         public void visitInnerClassType(String name) {
324             // This is not a fully qualified class name, ignore.
325             super.visitInnerClassType(name);
326         }
327         
328     }
329 }