/******************************************************************************* * Copyright (c) 2011 Gerd Wuetherich (gerd@gerd-wuetherich.de). * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Gerd Wuetherich (gerd@gerd-wuetherich.de) - initial API and implementation ******************************************************************************/ package org.bundlemaker.core.parser.bytecode.asm; import org.bundlemaker.core.jtype.TypeEnum; import org.eclipse.core.runtime.Assert; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.EmptyVisitor; /** * <p> * </p> */ public class ArtefactAnalyserClassVisitor extends EmptyVisitor implements ClassVisitor { /** - */ private static final String CLASS_NAME_PREFIX = "class$"; /** the ASM type */ private Type _type; /** - */ private AsmReferenceRecorder _recorder; /** - */ private boolean _analyzeReferences = false; /** * <p> * Creates a new instance of type {@link ArtefactAnalyserClassVisitor}. * </p> * * @param recorder */ public ArtefactAnalyserClassVisitor(AsmReferenceRecorder recorder, boolean analyzeReferences) { Assert.isNotNull(recorder); _recorder = recorder; _analyzeReferences = analyzeReferences; } public void visitSource(final String source, final String debug) { // System.out.println(source + " : " + debug); } /** * @inheritDoc */ @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { // get the type _type = Type.getObjectType(name); // get the abstract flag boolean abstractType = ((access & Opcodes.ACC_ABSTRACT)!=0); // get the type type TypeEnum typeEnum = null; if ((access & Opcodes.ACC_ENUM) != 0) { typeEnum = TypeEnum.ENUM; } else if ((access & Opcodes.ACC_ANNOTATION) != 0) { typeEnum = TypeEnum.ANNOTATION; } else if ((access & Opcodes.ACC_INTERFACE) != 0) { typeEnum = TypeEnum.INTERFACE; abstractType = true; } else { typeEnum = TypeEnum.CLASS; } // get the fully qualified name String fullyQualifiedName = VisitorUtils.getFullyQualifiedTypeName(_type); // record the contained type _recorder.recordContainedType(fullyQualifiedName, typeEnum,abstractType); if (_analyzeReferences) { // super type // TODO: USES Type superType = Type.getObjectType(superName); VisitorUtils.recordReferencedTypes(_recorder, true, false, false, superType); // for (String interfaceName : interfaces) { // implemented interfaces // TODO: USES Type implementsType = Type.getObjectType(interfaceName); VisitorUtils.recordReferencedTypes(_recorder, false, true, false, implementsType); } } } /** * @inheritDoc */ @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { // if (!_analyzeReferences) { return null; } // class annotation // TODO: USES Type type = Type.getType(desc); VisitorUtils.recordReferencedTypes(_recorder, false, false, true, type); return null; } /** * @inheritDoc */ @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { // if (!_analyzeReferences) { return null; } Type t = Type.getType(desc); if ((access & Opcodes.ACC_SYNTHETIC) == Opcodes.ACC_SYNTHETIC) { if (Class.class.getName().equals(t.getClassName())) { if (name != null && name.startsWith(CLASS_NAME_PREFIX)) { name = name.substring(CLASS_NAME_PREFIX.length()); name = name.replace('$', '.'); int lastDotIndex = name.lastIndexOf('.'); for (int i = 0; i < lastDotIndex; i++) { if (Character.isUpperCase(name.charAt(i))) { if (i == 0) { return null; } if (name.charAt(i - 1) == '.') { name = name.substring(0, i) + name.substring(i).replace('.', '$'); break; } } } if (Character.isJavaIdentifierStart(name.charAt(0))) { // no uses VisitorUtils.recordReferencedTypes(_recorder, false, false, false, name); } } } } // no uses VisitorUtils.recordReferencedTypes(_recorder, false, false, false, t); // return new ArtefactAnalyserFieldVisitor(_recorder); } /** * @inheritDoc */ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { // if (!_analyzeReferences) { return null; } VisitorUtils.recordReferencedTypes(_recorder, false, false, false, Type.getArgumentTypes(desc)); VisitorUtils.recordReferencedTypes(_recorder, false, false, false, Type.getReturnType(desc)); if (exceptions != null) { for (String exception : exceptions) { VisitorUtils.recordReferencedTypes(_recorder, false, false, false, Type.getObjectType(exception)); } } // TODO uses // if (access != Opcodes.ACC_PRIVATE) { // VisitorUtils.recordUses(this.partialManifest, this._type, // Type.getArgumentTypes(desc)); // VisitorUtils.recordUses(this.partialManifest, this._type, // Type.getReturnType(desc)); // if (exceptions != null) { // for (String exception : exceptions) { // VisitorUtils.recordUses(this.partialManifest, this._type, // Type.getObjectType(exception)); // } // } // } return new ArtefactAnalyserMethodVisitor(_recorder); } }