Package org.jetbrains.ether.dependencyView

Source Code of org.jetbrains.ether.dependencyView.ClassfileAnalyzer$ClassCrawler$AnnotationRetentionPolicyCrawler

package org.jetbrains.ether.dependencyView;

import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
import org.jetbrains.ether.Pair;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.EmptyVisitor;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;

import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.util.*;

/**
* Created by IntelliJ IDEA.
* User: db
* Date: 31.01.11
* Time: 2:00
* To change this template use File | Settings | File Templates.
*/

public class ClassfileAnalyzer {
    private static class Holder<T> {
        private T x = null;

        public void set(final T x) {
            this.x = x;
        }

        public T get() {
            return x;
        }
    }

    private static class ClassCrawler extends EmptyVisitor {
        private class AnnotationRetentionPolicyCrawler implements AnnotationVisitor {
            public void visit(String name, Object value) {
            }

            public void visitEnum(String name, String desc, String value) {
                policy = RetentionPolicy.valueOf(value);
            }

            public AnnotationVisitor visitAnnotation(String name, String desc) {
                return null;
            }

            public AnnotationVisitor visitArray(String name) {
                return null;
            }

            public void visitEnd() {
            }
        }

        private class AnnotationTargetCrawler implements AnnotationVisitor {
            public void visit(String name, Object value) {
            }

            public void visitEnum(final String name, String desc, final String value) {
                targets.add(ElementType.valueOf(value));
            }

            public AnnotationVisitor visitAnnotation(String name, String desc) {
                return this;
            }

            public AnnotationVisitor visitArray(String name) {
                return this;
            }

            public void visitEnd() {
            }
        }

        private class AnnotationCrawler implements AnnotationVisitor {
            private final TypeRepr.ClassType type;
            private final ElementType target;

            private final Set<StringCache.S> usedArguments = new HashSet<StringCache.S>();

            private AnnotationCrawler(final TypeRepr.ClassType type, final ElementType target) {
                this.type = type;
                this.target = target;
                annotationTargets.put(type, target);
                usages.addUsage(classNameHolder.get(), UsageRepr.createClassUsage(type.className));
            }

            private String getMethodDescr(final Object value) {
                if (value instanceof Type) {
                    return "()Ljava/lang/Class;";
                }

                final String name = Type.getType(value.getClass()).getInternalName();

                if (name.equals("java/lang/Integer")) {
                    return "()I;";
                }

                if (name.equals("java/lang/Short")) {
                    return "()S;";
                }

                if (name.equals("java/lang/Long")) {
                    return "()J;";
                }

                if (name.equals("java/lang/Byte")) {
                    return "()B;";
                }

                if (name.equals("java/lang/Char")) {
                    return "()C;";
                }

                if (name.equals("java/lang/Boolean")) {
                    return "()Z;";
                }

                if (name.equals("java/lang/Float")) {
                    return "()F;";
                }

                if (name.equals("java/lang/Double")) {
                    return "()D;";
                }

                final String s = "()L" + name + ";";

                return s;
            }

            public void visit(String name, Object value) {
                usages.addUsage(classNameHolder.get(), UsageRepr.createMethodUsage(name, type.className.value, getMethodDescr(value)));
                usedArguments.add(StringCache.get(name));
            }

            public void visitEnum(String name, String desc, String value) {
                usages.addUsage(classNameHolder.get(), UsageRepr.createMethodUsage(name, type.className.value, "()" + desc));
                usedArguments.add(StringCache.get(name));
            }

            public AnnotationVisitor visitAnnotation(String name, String desc) {
                return new AnnotationCrawler((TypeRepr.ClassType) TypeRepr.getType(desc), target);
            }

            public AnnotationVisitor visitArray(String name) {
                usedArguments.add(StringCache.get(name));
                return this;
            }

            public void visitEnd() {
                final Set<StringCache.S> s = annotationArguments.get(type);

                if (s == null) {
                    annotationArguments.put(type, usedArguments);
                } else {
                    s.retainAll(usedArguments);
                }
            }
        }

        private void processSignature(final String sig) {
            if (sig != null)
                new SignatureReader(sig).accept(signatureCrawler);
        }

        private final SignatureVisitor signatureCrawler = new SignatureVisitor() {
            public void visitFormalTypeParameter(String name) {
                return;
            }

            public SignatureVisitor visitClassBound() {
                return this;
            }

            public SignatureVisitor visitInterfaceBound() {
                return this;
            }

            public SignatureVisitor visitSuperclass() {
                return this;
            }

            public SignatureVisitor visitInterface() {
                return this;
            }

            public SignatureVisitor visitParameterType() {
                return this;
            }

            public SignatureVisitor visitReturnType() {
                return this;
            }

            public SignatureVisitor visitExceptionType() {
                return this;
            }

            public void visitBaseType(char descriptor) {
                return;
            }

            public void visitTypeVariable(String name) {
                return;
            }

            public SignatureVisitor visitArrayType() {
                return this;
            }

            public void visitInnerClassType(String name) {
                return;
            }

            public void visitTypeArgument() {
                return;
            }

            public SignatureVisitor visitTypeArgument(char wildcard) {
                return this;
            }

            public void visitEnd() {
            }

            public void visitClassType(String name) {
                usages.addUsage(classNameHolder.get(), UsageRepr.createClassUsage(name));
            }
        };

        Boolean takeIntoAccount = false;

        final StringCache.S fileName;
        int access;
        StringCache.S name;
        String superClass;
        String[] interfaces;
        String signature;
        StringCache.S sourceFile;

        final Holder<String> classNameHolder = new Holder<String>();

        final Set<MethodRepr> methods = new HashSet<MethodRepr>();
        final Set<FieldRepr> fields = new HashSet<FieldRepr>();
        final List<String> nestedClasses = new ArrayList<String>();
        final UsageRepr.Cluster usages = new UsageRepr.Cluster();
        final Set<UsageRepr.Usage> annotationUsages = new HashSet<UsageRepr.Usage>();
        final Set<ElementType> targets = new HashSet<ElementType>();
        RetentionPolicy policy = null;

        private static FoxyMap.CollectionConstructor<ElementType> elementTypeSetConstructor = new FoxyMap.CollectionConstructor<ElementType>() {
            public Collection<ElementType> create() {
                return new HashSet<ElementType>();
            }
        };

        final Map<TypeRepr.ClassType, Set<StringCache.S>> annotationArguments = new HashMap<TypeRepr.ClassType, Set<StringCache.S>>();
        final FoxyMap<TypeRepr.ClassType, ElementType> annotationTargets = new FoxyMap<TypeRepr.ClassType, ElementType>(elementTypeSetConstructor);

        public ClassCrawler(final StringCache.S fn) {
            fileName = fn;
        }

        private boolean notPrivate(final int access) {
            return (access & Opcodes.ACC_PRIVATE) == 0;
        }

        public Pair<ClassRepr, Pair<UsageRepr.Cluster, Set<UsageRepr.Usage>>> getResult() {
            final ClassRepr repr = takeIntoAccount ?
                    new ClassRepr(access, sourceFile, fileName, name, signature, superClass, interfaces, nestedClasses, fields, methods, targets, policy) : null;

            if (repr != null) {
                repr.updateClassUsages(usages.getUsages());
            }

            return new Pair<ClassRepr, Pair<UsageRepr.Cluster, Set<UsageRepr.Usage>>>(repr, new Pair<UsageRepr.Cluster, Set<UsageRepr.Usage>>(usages, annotationUsages));
        }

        @Override
        public void visit(int version, int a, String n, String sig, String s, String[] i) {
            takeIntoAccount = notPrivate(a);

            access = a;
            name = StringCache.get(n);
            signature = sig;
            superClass = s;
            interfaces = i;

            classNameHolder.set(n);

            if (superClass != null) {
                usages.addUsage(classNameHolder.get(), UsageRepr.createClassUsage(StringCache.get(superClass)));
                usages.addUsage(classNameHolder.get(), UsageRepr.createClassExtendsUsage(StringCache.get(superClass)));
            }

            if (interfaces != null) {
                for (String it : interfaces) {
                    usages.addUsage(classNameHolder.get(), UsageRepr.createClassUsage(StringCache.get(it)));
                    usages.addUsage(classNameHolder.get(), UsageRepr.createClassExtendsUsage(StringCache.get(it)));
                }
            }

            processSignature(sig);
        }

        @Override
        public void visitEnd() {
            for (TypeRepr.ClassType type : annotationTargets.keySet()) {
                final Collection<ElementType> targets = annotationTargets.foxyGet(type);
                final Set<StringCache.S> usedArguments = annotationArguments.get(type);

                annotationUsages.add(UsageRepr.createAnnotationUsage(type, usedArguments, targets));
            }
        }

        @Override
        public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
            if (desc.equals("Ljava/lang/annotation/Target;")) {
                return new AnnotationTargetCrawler();
            }

            if (desc.equals("Ljava/lang/annotation/Retention;")) {
                return new AnnotationRetentionPolicyCrawler();
            }

            return new AnnotationCrawler((TypeRepr.ClassType) TypeRepr.getType(desc), (access & Opcodes.ACC_ANNOTATION) > 0 ? ElementType.ANNOTATION_TYPE : ElementType.TYPE);
        }

        @Override
        public void visitSource(String source, String debug) {
            sourceFile = StringCache.get(source);
        }

        @Override
        public FieldVisitor visitField(int access, String n, String desc, String signature, Object value) {
            processSignature(signature);

            if (notPrivate(access)) {
                fields.add(new FieldRepr(access, n, desc, signature, value));
            }

            return new EmptyVisitor() {
                @Override
                public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                    return new AnnotationCrawler((TypeRepr.ClassType) TypeRepr.getType(desc), ElementType.FIELD);
                }
            };
        }

        @Override
        public MethodVisitor visitMethod(final int access, final String n, final String desc, final String signature, final String[] exceptions) {
            final Holder<Object> defaultValue = new Holder<Object>();

            processSignature(signature);

            return new EmptyVisitor() {
                @Override
                public void visitEnd() {
                    if (notPrivate(access)) {
                        methods.add(new MethodRepr(access, n, signature, desc, exceptions, defaultValue.get()));
                    }
                }

                @Override
                public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                    return new AnnotationCrawler((TypeRepr.ClassType) TypeRepr.getType(desc), n.equals("<init>") ? ElementType.CONSTRUCTOR : ElementType.METHOD);
                }

                @Override
                public AnnotationVisitor visitAnnotationDefault() {
                    return new EmptyVisitor() {
                        public void visit(String name, Object value) {
                            defaultValue.set(value);
                        }
                    };
                }

                @Override
                public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
                    return new AnnotationCrawler((TypeRepr.ClassType) TypeRepr.getType(desc), ElementType.PARAMETER);
                }

                @Override
                public void visitMultiANewArrayInsn(String desc, int dims) {
                    final TypeRepr.ArrayType typ = (TypeRepr.ArrayType) TypeRepr.getType(desc);
                    final TypeRepr.AbstractType element = typ.getDeepElementType();

                    if (element instanceof TypeRepr.ClassType) {
                        usages.addUsage(classNameHolder.get(), UsageRepr.createClassUsage(((TypeRepr.ClassType) element).className));
                        usages.addUsage(classNameHolder.get(), UsageRepr.createClassNewUsage(((TypeRepr.ClassType) element).className));
                    }

                    typ.updateClassUsages(usages.getUsages());

                    super.visitMultiANewArrayInsn(desc, dims);
                }

                @Override
                public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
                    processSignature(signature);
                    TypeRepr.getType(desc).updateClassUsages(usages.getUsages());
                    super.visitLocalVariable(name, desc, signature, start, end, index);
                }

                @Override
                public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
                    if (type != null) {
                        TypeRepr.createClassType(type).updateClassUsages(usages.getUsages());
                    }

                    super.visitTryCatchBlock(start, end, handler, type);
                }

                @Override
                public void visitTypeInsn(int opcode, String type) {
                    final TypeRepr.AbstractType typ = type.startsWith("[") ? TypeRepr.getType(type) : TypeRepr.createClassType(type);

                    if (opcode == Opcodes.NEW) {
                        usages.addUsage(classNameHolder.get(), UsageRepr.createClassUsage(((TypeRepr.ClassType) typ).className));
                        usages.addUsage(classNameHolder.get(), UsageRepr.createClassNewUsage(((TypeRepr.ClassType) typ).className));
                    } else if (opcode == Opcodes.ANEWARRAY) {
                        if (typ instanceof TypeRepr.ClassType) {
                            usages.addUsage(classNameHolder.get(), UsageRepr.createClassUsage(((TypeRepr.ClassType) typ).className));
                            usages.addUsage(classNameHolder.get(), UsageRepr.createClassNewUsage(((TypeRepr.ClassType) typ).className));
                        }
                    }

                    typ.updateClassUsages(usages.getUsages());

                    super.visitTypeInsn(opcode, type);
                }

                @Override
                public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                    if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) {
                        usages.addUsage(classNameHolder.get(), UsageRepr.createFieldAssignUsage(name, owner, desc));
                    }
                    usages.addUsage(classNameHolder.get(), UsageRepr.createFieldUsage(name, owner, desc));
                    super.visitFieldInsn(opcode, owner, name, desc);
                }

                @Override
                public void visitMethodInsn(int opcode, String owner, String name, String desc) {
                    usages.addUsage(classNameHolder.get(), UsageRepr.createMethodUsage(name, owner, desc));
                    super.visitMethodInsn(opcode, owner, name, desc);
                }
            };
        }

        @Override
        public void visitInnerClass(String name, String outerName, String innerName, int access) {
            if (outerName != null && outerName.equals(name) && notPrivate(access)) {
                nestedClasses.add(innerName);
            }
        }
    }

    public static Pair<ClassRepr, Pair<UsageRepr.Cluster, Set<UsageRepr.Usage>>> analyze(final StringCache.S fileName, final ClassReader cr) {
        final ClassCrawler visitor = new ClassCrawler(fileName);

        cr.accept(visitor, 0);

        return visitor.getResult();
    }
}
TOP

Related Classes of org.jetbrains.ether.dependencyView.ClassfileAnalyzer$ClassCrawler$AnnotationRetentionPolicyCrawler

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.