Package com.buschmais.jqassistant.plugin.java.impl.scanner.visitor

Source Code of com.buschmais.jqassistant.plugin.java.impl.scanner.visitor.ClassVisitor

package com.buschmais.jqassistant.plugin.java.impl.scanner.visitor;

import org.objectweb.asm.Attribute;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;

import com.buschmais.jqassistant.plugin.java.api.model.AccessModifierDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.AnnotationTypeDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.AnnotationValueDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.ClassFileDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.ClassTypeDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.EnumTypeDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.FieldDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.InterfaceTypeDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.MethodDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.ParameterDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.TypeDescriptor;
import com.buschmais.jqassistant.plugin.java.api.model.VisibilityModifier;
import com.buschmais.jqassistant.plugin.java.api.scanner.SignatureHelper;

public class ClassVisitor extends org.objectweb.asm.ClassVisitor {

    private ClassFileDescriptor typeDescriptor;
    private VisitorHelper visitorHelper;

    public ClassVisitor(VisitorHelper visitorHelper) {
        super(Opcodes.ASM5);
        this.visitorHelper = visitorHelper;
    }

    /**
     * Return the type descriptor created by visiting the class.
     *
     * @return The type descriptor.
     */
    public ClassFileDescriptor getTypeDescriptor() {
        return typeDescriptor;
    }

    @Override
    public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
        Class<? extends ClassFileDescriptor> javaType = getJavaType(access);
        typeDescriptor = visitorHelper.getTypeDescriptor(SignatureHelper.getObjectType(name), javaType);
        if (hasFlag(access, Opcodes.ACC_ABSTRACT) && !hasFlag(access, Opcodes.ACC_INTERFACE)) {
            typeDescriptor.setAbstract(Boolean.TRUE);
        }
        setModifiers(access, typeDescriptor);
        if (signature == null) {
            if (superName != null) {
                typeDescriptor.setSuperClass(visitorHelper.getTypeDescriptor(SignatureHelper.getObjectType(superName)));
            }
            for (int i = 0; interfaces != null && i < interfaces.length; i++) {
                typeDescriptor.addInterface(visitorHelper.getTypeDescriptor(SignatureHelper.getObjectType(interfaces[i])));
            }
        } else {
            new SignatureReader(signature).accept(new ClassSignatureVisitor(typeDescriptor, visitorHelper));
        }
    }

    @Override
    public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {
        final FieldDescriptor fieldDescriptor = visitorHelper.getFieldDescriptor(typeDescriptor, SignatureHelper.getFieldSignature(name, desc));
        typeDescriptor.addDeclaredField(fieldDescriptor);
        fieldDescriptor.setName(name);
        fieldDescriptor.setVolatile(hasFlag(access, Opcodes.ACC_VOLATILE));
        fieldDescriptor.setTransient(hasFlag(access, Opcodes.ACC_TRANSIENT));
        setModifiers(access, fieldDescriptor);
        if (signature == null) {
            TypeDescriptor type = visitorHelper.getTypeDescriptor(SignatureHelper.getType((desc)));
            fieldDescriptor.setType(type);
        } else {
            new SignatureReader(signature).accept(new AbstractTypeSignatureVisitor<FieldDescriptor>(fieldDescriptor, visitorHelper) {
                @Override
                public SignatureVisitor visitArrayType() {
                    return new DependentTypeSignatureVisitor(fieldDescriptor, visitorHelper);
                }

                @Override
                public SignatureVisitor visitTypeArgument(char wildcard) {
                    return new DependentTypeSignatureVisitor(fieldDescriptor, visitorHelper);
                }

                @Override
                public SignatureVisitor visitSuperclass() {
                    return this;
                }

                @Override
                public void visitEnd(TypeDescriptor resolvedTypeDescriptor) {
                    fieldDescriptor.setType(resolvedTypeDescriptor);
                }
            });
        }
        if (value instanceof org.objectweb.asm.Type) {
            visitorHelper.addDependency(fieldDescriptor, SignatureHelper.getType((org.objectweb.asm.Type) value));
        }
        return new FieldVisitor(fieldDescriptor, visitorHelper);
    }

    @Override
    public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
        MethodDescriptor methodDescriptor = visitorHelper.getMethodDescriptor(typeDescriptor, SignatureHelper.getMethodSignature(name, desc));
        typeDescriptor.addDeclaredMethod(methodDescriptor);
        methodDescriptor.setName(name);
        setModifiers(access, methodDescriptor);
        if (hasFlag(access, Opcodes.ACC_ABSTRACT)) {
            methodDescriptor.setAbstract(Boolean.TRUE);
        }
        if (hasFlag(access, Opcodes.ACC_NATIVE)) {
            methodDescriptor.setNative(Boolean.TRUE);
        }
        if (signature == null) {
            String returnType = SignatureHelper.getType(Type.getReturnType(desc));
            methodDescriptor.setReturns(visitorHelper.getTypeDescriptor(returnType));
            org.objectweb.asm.Type[] types = org.objectweb.asm.Type.getArgumentTypes(desc);
            for (int i = 0; i < types.length; i++) {
                ParameterDescriptor parameterDescriptor = visitorHelper.addParameterDescriptor(methodDescriptor, i);
                String parameterType = SignatureHelper.getType(types[i]);
                parameterDescriptor.setType(visitorHelper.getTypeDescriptor(parameterType));
            }
        } else {
            new SignatureReader(signature).accept(new MethodSignatureVisitor(methodDescriptor, visitorHelper));
        }
        for (int i = 0; exceptions != null && i < exceptions.length; i++) {
            TypeDescriptor exception = visitorHelper.getTypeDescriptor(SignatureHelper.getObjectType(exceptions[i]));
            methodDescriptor.getDeclaredThrowables().add(exception);
        }
        return new MethodVisitor(methodDescriptor, visitorHelper);
    }

    private void setModifiers(final int access, AccessModifierDescriptor descriptor) {
        VisibilityModifier visibility = getVisibility(access);
        descriptor.setVisibility(visibility.getValue());
        if (hasFlag(access, Opcodes.ACC_SYNTHETIC)) {
            descriptor.setSynthetic(Boolean.TRUE);
        }
        if (hasFlag(access, Opcodes.ACC_FINAL)) {
            descriptor.setFinal(Boolean.TRUE);
        }
        if (hasFlag(access, Opcodes.ACC_STATIC)) {
            descriptor.setStatic(Boolean.TRUE);
        }
    }

    @Override
    public void visitSource(final String source, final String debug) {
    }

    @Override
    public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) {
        addInnerClass(typeDescriptor, visitorHelper.getTypeDescriptor(SignatureHelper.getObjectType(name)));
    }

    @Override
    public void visitOuterClass(final String owner, final String name, final String desc) {
        addInnerClass(visitorHelper.getTypeDescriptor(SignatureHelper.getObjectType(owner)), typeDescriptor);
    }

    // ---------------------------------------------

    @Override
    public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
        AnnotationValueDescriptor annotationDescriptor = visitorHelper.addAnnotation(typeDescriptor, SignatureHelper.getType(desc));
        return new AnnotationVisitor(annotationDescriptor, visitorHelper);
    }

    @Override
    public void visitAttribute(Attribute attribute) {
    }

    @Override
    public void visitEnd() {
    }

    /**
     * Checks whether the value contains the flag.
     *
     * @param value
     *            the value
     * @param flag
     *            the flag
     * @return <code>true</code> if (value & flag) == flag, otherwise
     *         <code>false</code>.
     */
    private boolean hasFlag(int value, int flag) {
        return (value & flag) == flag;
    }

    /**
     * Returns the AccessModifier for the flag pattern.
     *
     * @param flags
     *            the flags
     * @return the AccessModifier
     */
    private VisibilityModifier getVisibility(int flags) {
        if (hasFlag(flags, Opcodes.ACC_PRIVATE)) {
            return VisibilityModifier.PRIVATE;
        } else if (hasFlag(flags, Opcodes.ACC_PROTECTED)) {
            return VisibilityModifier.PROTECTED;
        } else if (hasFlag(flags, Opcodes.ACC_PUBLIC)) {
            return VisibilityModifier.PUBLIC;
        } else {
            return VisibilityModifier.DEFAULT;
        }
    }

    /**
     * Determine the types label to be applied to a class node.
     *
     * @param flags
     *            The access flags.
     * @return The types label.
     */
    private Class<? extends ClassFileDescriptor> getJavaType(int flags) {
        if (hasFlag(flags, Opcodes.ACC_ANNOTATION)) {
            return AnnotationTypeDescriptor.class;
        } else if (hasFlag(flags, Opcodes.ACC_ENUM)) {
            return EnumTypeDescriptor.class;
        } else if (hasFlag(flags, Opcodes.ACC_INTERFACE)) {
            return InterfaceTypeDescriptor.class;
        }
        return ClassTypeDescriptor.class;
    }

    /**
     * Adds an inner class relation.
     *
     * @param outerClass
     *            The outer class.
     * @param innerClass
     *            The inner class.
     */
    private void addInnerClass(TypeDescriptor outerClass, TypeDescriptor innerClass) {
        if (!innerClass.equals(outerClass)) {
            outerClass.addDeclaredInnerClass(innerClass);
        }
    }
}
TOP

Related Classes of com.buschmais.jqassistant.plugin.java.impl.scanner.visitor.ClassVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.