/*** * Copyright (c) 2000-2007 INRIA, France Telecom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /****************************************************************************** * Portions modified by VMware are provided under the EPL and ASL * Copyright (c) 2002, 2010, VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 * is available at http://www.opensource.org/licenses/apache2.0.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * VMware Inc. *****************************************************************************/ package org.eclipse.gemini.blueprint.test.internal.util; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; /** * ASM based class for determining a class imports. The code is heavily based on an Eugene Kuleshov's ASM <a * href="http://asm.objectweb.org/doc/tutorial-asm-2.0.html">tutorial</a>. * * <p/>The main differences from the original source in the article are the 1.4 compatibility, the handling of class * objects not instantiated (MyClass.class.getName()) as these are specially handled by the compiler and analysis of * inner classes, including ones from different packages. * * @author Costin Leau */ public class DependencyVisitor implements AnnotationVisitor, SignatureVisitor, ClassVisitor, FieldVisitor, MethodVisitor { private Set packages = new LinkedHashSet(); private Map groups = new LinkedHashMap(); private Map current; private String tempLdc; private String ownerName; private Set innerClasses = new LinkedHashSet(4); private static final String CLASS_NAME = Class.class.getName(); public Map getGlobals() { return groups; } public Set getPackages() { return packages; } public Set getInnerClasses() { return innerClasses; } // ClassVisitor public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { tempLdc = null; this.ownerName = name; String p = getGroupKey(name); current = (Map) groups.get(p); if (current == null) { current = new LinkedHashMap(); groups.put(p, current); } if (signature == null) { addName(superName); addNames(interfaces); } else { addSignature(signature); } } public AnnotationVisitor visitAnnotation(String desc, boolean visible) { tempLdc = null; addDesc(desc); return this; } public void visitAttribute(Attribute attr) { tempLdc = null; } public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { tempLdc = null; if (signature == null) { addDesc(desc); } else { addTypeSignature(signature); } if (value instanceof Type) addType((Type) value); return this; } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { tempLdc = null; if (signature == null) { addMethodDesc(desc); } else { addSignature(signature); } addNames(exceptions); return this; } public void visitSource(String source, String debug) { tempLdc = null; } public void visitInnerClass(String name, String outerName, String innerName, int access) { tempLdc = null; addName(name); addName(outerName); if (!ownerName.equals(name)) { innerClasses.add(name); } } public void visitOuterClass(String owner, String name, String desc) { tempLdc = null; // addName(owner); // addMethodDesc(desc); } // MethodVisitor public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { tempLdc = null; addDesc(desc); return this; } public void visitTypeInsn(int opcode, String desc) { tempLdc = null; if (desc.charAt(0) == '[') addDesc(desc); else addName(desc); } public void visitFieldInsn(int opcode, String owner, String name, String desc) { tempLdc = null; addName(owner); addDesc(desc); } public void visitMethodInsn(int opcode, String owner, String name, String desc) { String returnType = Type.getReturnType(desc).getClassName(); if (opcode == Opcodes.INVOKESTATIC && CLASS_NAME.equals(returnType)) { if (tempLdc != null) addName(tempLdc.replace('.', '/')); } tempLdc = null; addName(owner); addMethodDesc(desc); } public void visitLdcInsn(Object cst) { tempLdc = null; if (cst instanceof Type) addType((Type) cst); else if (cst instanceof String) { tempLdc = (String) cst; } } public void visitMultiANewArrayInsn(String desc, int dims) { tempLdc = null; addDesc(desc); } public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { tempLdc = null; addTypeSignature(signature); } public AnnotationVisitor visitAnnotationDefault() { tempLdc = null; return this; } public void visitCode() { tempLdc = null; } public void visitInsn(int opcode) { tempLdc = null; } public void visitIntInsn(int opcode, int operand) { tempLdc = null; } public void visitVarInsn(int opcode, int var) { tempLdc = null; } public void visitJumpInsn(int opcode, Label label) { tempLdc = null; } public void visitLabel(Label label) { tempLdc = null; } public void visitIincInsn(int var, int increment) { tempLdc = null; } public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { tempLdc = null; } public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { tempLdc = null; } public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { tempLdc = null; addName(type); } public void visitLineNumber(int line, Label start) { tempLdc = null; } public void visitMaxs(int maxStack, int maxLocals) { tempLdc = null; } // AnnotationVisitor public void visit(String name, Object value) { tempLdc = null; if (value instanceof Type) addType((Type) value); } public void visitEnum(String name, String desc, String value) { tempLdc = null; addDesc(desc); } public AnnotationVisitor visitAnnotation(String name, String desc) { tempLdc = null; addDesc(desc); return this; } public AnnotationVisitor visitArray(String name) { tempLdc = null; return this; } // SignatureVisitor public void visitFormalTypeParameter(String name) { tempLdc = null; } public SignatureVisitor visitClassBound() { tempLdc = null; return this; } public SignatureVisitor visitInterfaceBound() { tempLdc = null; return this; } public SignatureVisitor visitSuperclass() { tempLdc = null; return this; } public SignatureVisitor visitInterface() { tempLdc = null; return this; } public SignatureVisitor visitParameterType() { tempLdc = null; return this; } public SignatureVisitor visitReturnType() { tempLdc = null; return this; } public SignatureVisitor visitExceptionType() { tempLdc = null; return this; } public void visitBaseType(char descriptor) { tempLdc = null; } public void visitTypeVariable(String name) { tempLdc = null; } public SignatureVisitor visitArrayType() { tempLdc = null; return this; } public void visitClassType(String name) { tempLdc = null; addName(name); } public void visitInnerClassType(String name) { tempLdc = null; addName(name); } public void visitTypeArgument() { tempLdc = null; } public SignatureVisitor visitTypeArgument(char wildcard) { tempLdc = null; return this; } // common public void visitEnd() { tempLdc = null; } // --------------------------------------------- private String getGroupKey(String name) { int n = name.lastIndexOf('/'); if (n > -1) name = name.substring(0, n); packages.add(name); return name; } private void addName(String name) { if (name == null) return; String p = getGroupKey(name); if (current.containsKey(p)) { current.put(p, new Integer(((Integer) current.get(p)).intValue() + 1)); } else { current.put(p, new Integer(1)); } } private void addNames(String[] names) { for (int i = 0; names != null && i < names.length; i++) addName(names[i]); } private void addDesc(String desc) { addType(Type.getType(desc)); } private void addMethodDesc(String desc) { addType(Type.getReturnType(desc)); Type[] types = Type.getArgumentTypes(desc); for (int i = 0; i < types.length; i++) addType(types[i]); } private void addType(Type t) { switch (t.getSort()) { case Type.ARRAY: addType(t.getElementType()); break; case Type.OBJECT: addName(t.getClassName().replace('.', '/')); break; } } private void addSignature(String signature) { if (signature != null) new SignatureReader(signature).accept(this); } private void addTypeSignature(String signature) { if (signature != null) new SignatureReader(signature).acceptType(this); } }