com.google.gwt.dev.javac.asm.CollectReferencesVisitor.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.dev.javac.asm.CollectReferencesVisitor.java

Source

/*
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev.javac.asm;

import com.google.gwt.dev.javac.asmbridge.EmptyVisitor;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
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;

import java.util.HashSet;
import java.util.Set;

/**
 * Collect all the types which are referenced by a particular class.
 */
public class CollectReferencesVisitor extends EmptyVisitor {

    /**
     * Collect type names from generic signatures.
     *
     * All we care about is picking up type names, so we just return ourselves for
     * nested visitors.
     */
    private class CollectGenericTypes extends SignatureVisitor {

        public CollectGenericTypes() {
            super(Opcodes.ASM6);
        }

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

        @Override
        public void visitBaseType(char descriptor) {
        }

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

        @Override
        public void visitClassType(String name) {
            referencedTypes.add(name);
        }

        @Override
        public void visitEnd() {
        }

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

        @Override
        public void visitFormalTypeParameter(String name) {
        }

        @Override
        public void visitInnerClassType(String name) {
        }

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

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

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

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

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

        @Override
        public void visitTypeArgument() {
        }

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

        @Override
        public void visitTypeVariable(String name) {
        }
    }

    CollectReferencesVisitor() {
        this.av = new AnnotationVisitor(Opcodes.ASM6, this.av) {
            @Override
            public void visitEnum(String name, String desc, String value) {
                addTypeIfClass(desc);
            }

            @Override
            public void visit(String name, Object value) {
                // don't mark this annotation as a reference or its arguments, so we can
                // handle binary-only annotations.
                // TODO(jat): consider implications of updating the annotation class
            }

        };
    }

    // internal names
    protected Set<String> referencedTypes = new HashSet<String>();

    public Set<String> getReferencedTypes() {
        return referencedTypes;
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        if (superName != null) {
            referencedTypes.add(superName);
        }
        if (interfaces != null) {
            for (String intf : interfaces) {
                referencedTypes.add(intf);
            }
        }
        collectTypesFromClassSignature(signature);
    }

    @Override
    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
        addTypeIfClass(desc);
        collectTypesFromFieldSignature(signature);
        // we don't use visitEnd, so we can just use ourselves for nested visitors
        return super.visitField(access, name, desc, signature, value);
    }

    /**
     * @param name internal name of the inner class
     * @param outerName internal name of the enclosing class
     */
    @Override
    public void visitInnerClass(String name, String outerName, String innerName, int access) {
        referencedTypes.add(name);
        if (outerName != null) {
            referencedTypes.add(outerName);
        }
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        for (Type type : Type.getArgumentTypes(desc)) {
            addTypeIfClass(type);
        }
        addTypeIfClass(Type.getReturnType(desc));
        collectTypesFromClassSignature(signature);
        // we don't use visitEnd, so we can just use ourselves for nested visitors
        return super.visitMethod(access, name, desc, signature, exceptions);
    }

    /**
     * @param owner internal name of owning class
     */
    @Override
    public void visitOuterClass(String owner, String name, String desc) {
        referencedTypes.add(owner);
    }

    protected void addTypeIfClass(String desc) {
        addTypeIfClass(Type.getType(desc));
    }

    protected void addTypeIfClass(Type type) {
        if (type.getSort() == Type.OBJECT) {
            referencedTypes.add(type.getInternalName());
        }
    }

    private void collectTypesFromClassSignature(String signature) {
        if (signature == null) {
            return;
        }
        SignatureReader reader = new SignatureReader(signature);
        reader.accept(new CollectGenericTypes());
    }

    private void collectTypesFromFieldSignature(String signature) {
        if (signature == null) {
            return;
        }
        SignatureReader reader = new SignatureReader(signature);
        reader.acceptType(new CollectGenericTypes());
    }
}