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

Java tutorial

Introduction

Here is the source code for com.google.gwt.dev.javac.asm.CollectClassDataTest.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.asm.CollectAnnotationData.AnnotationData;
import com.google.gwt.dev.javac.asm.CollectClassData.ClassType;
import com.google.gwt.dev.javac.asm.CollectClassDataTest.Pseudo$Inner.Deepest;
import com.google.gwt.dev.javac.asmbridge.EmptyVisitor;
import com.google.gwt.dev.javac.typemodel.test.PrimitiveValuesAnnotation;
import com.google.gwt.dev.javac.typemodel.test.TestAnnotation;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import java.util.List;

/**
 * Tests for {@link CollectClassData}.
 */
public class CollectClassDataTest extends AsmTestCase {

    /**
     * Test class used in {@link CollectClassData#testLongDoubleArgs}.
     */
    static class LongDoubleArgs {

        @SuppressWarnings("unused")
        public LongDoubleArgs(int x, long y, double z, Object o) {
        }

        @SuppressWarnings("unused")
        public void longDoubleMethod(int xx, long yy, double zz, String s) {
        }
    }

    /**
     * Test class used in {@link CollectClassData#testOne}.
     */
    public static class One extends EmptyVisitor {

        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            new EmptyVisitor() {
                @Override
                public void visit(int version, int access, String name, String signature, String superName,
                        String[] interfaces) {
                }
            };
            return new CollectAnnotationData(desc, visible);
        }
    }

    /**
     * Test class used in {@link CollectClassData#testPseudoInner}.
     */
    protected static class Pseudo$Inner {

        static class Deepest {
        }
    }

    /**
     * Test class used in {@link CollectClassData#testTwo}.
     */
    @PrimitiveValuesAnnotation(b = 42, i = 42)
    protected static class Two {

        /**
         * Test class used in {@link CollectClassData#testTwoInner}.
         */
        public class TwoInner {
        }

        private final String field;

        @TestAnnotation("field")
        private final String annotatedField;

        public Two(int a) {
            this(a, null);
        }

        @TestAnnotation("foo")
        public String foo(int a) throws IllegalStateException {
            return annotatedField;
        }

        public Two(int a, String b) {
            new TwoInner();
            field = b;
            annotatedField = field;
        }
    }

    /**
     * Test local classes.
     */
    public static class Three {

        public int foo;

        /**
         * Static method that has a local class in it.
         */
        public static void methodWithLocalStatic() {
            class Foo {
            }

            Foo x = new Foo();
        }

        /**
         * Method that has a local class in it.
         */
        public void methodWithLocal() {
            class Foo {
                Foo() {
                    foo = 1;
                }
            }

            Foo x = new Foo();
        }
    }

    public void testAnonymous() {
        CollectClassData cd = collect(One.class.getName() + "$1");
        // Don't access on anonymous classes, it varies among compilers
        // assertEquals(0, cd.getAccess() & ~Opcodes.ACC_SUPER);
        assertEquals(ClassType.Anonymous, cd.getClassType());
        assertEquals(0, cd.getFields().size());
        List<CollectMethodData> methods = cd.getMethods();
        assertEquals(2, methods.size());
        assertEquals(null, cd.getNestedSourceName());
    }

    public void testOne() {
        CollectClassData cd = collect(One.class);
        // Don't check for super bit, as it will depend on the JDK used to compile.
        assertEquals(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, cd.getAccess() & ~Opcodes.ACC_SUPER);
        assertEquals(ClassType.Nested, cd.getClassType());
        assertEquals(0, cd.getFields().size());
        assertEquals(0, cd.getInterfaceInternalNames().length);
        assertEquals(0, cd.getAnnotations().size());
        assertEquals("com/google/gwt/dev/javac/asmbridge/EmptyVisitor", cd.getSuperInternalName());
        assertEquals("CollectClassDataTest.One", cd.getNestedSourceName());

        List<CollectMethodData> methods = cd.getMethods();
        assertEquals(2, methods.size());
        // TODO(jat): Is it safe to assume the implicit constructor is always first?
        CollectMethodData method = methods.get(0);
        Type[] argTypes = method.getArgTypes();
        String[] argNames = method.getArgNames();
        assertEquals("<init>", method.getName());
        assertEquals(0, argTypes.length);
        assertEquals(0, argNames.length);
        assertEquals(0, method.getArgAnnotations().length);
        assertEquals(0, method.getAnnotations().size());
        assertEquals(0, method.getExceptions().length);

        method = methods.get(1);
        argTypes = method.getArgTypes();
        argNames = method.getArgNames();
        assertEquals("visitAnnotation", method.getName());
        assertEquals(2, argTypes.length);
        assertEquals("java.lang.String", argTypes[0].getClassName());
        assertEquals("boolean", argTypes[1].getClassName());
        assertEquals(2, argNames.length);
        assertEquals("desc", argNames[0]);
        assertEquals("visible", argNames[1]);
        assertEquals(2, method.getArgAnnotations().length);
        assertEquals(0, method.getArgAnnotations()[0].size());
        assertEquals(0, method.getArgAnnotations()[1].size());
        // Note that @Override is a source-only annotation
        assertEquals(0, method.getAnnotations().size());
        assertEquals(0, method.getExceptions().length);
    }

    public void testTopLevel() {
        CollectClassData cd = collect(CollectClassDataTest.class);
        // Don't check for super bit, as it will depend on the JDK used to compile.
        assertEquals(Opcodes.ACC_PUBLIC, cd.getAccess() & ~Opcodes.ACC_SUPER);
        assertEquals(ClassType.TopLevel, cd.getClassType());
        assertEquals("CollectClassDataTest", cd.getNestedSourceName());
    }

    public void testTwo() {
        CollectClassData cd = collect(Two.class);
        // Don't check for super bit, as it will depend on the JDK used to compile.
        assertEquals(Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC, cd.getAccess() & ~Opcodes.ACC_SUPER);
        assertEquals(ClassType.Nested, cd.getClassType());
        List<CollectFieldData> fields = cd.getFields();
        assertEquals(2, fields.size());
        CollectFieldData field = fields.get(0);
        assertEquals("field", field.getName());
        assertEquals("Ljava/lang/String;", field.getDesc());
        List<CollectAnnotationData> annotations = field.getAnnotations();
        assertEquals(0, annotations.size());
        field = fields.get(1);
        assertEquals("annotatedField", field.getName());
        assertEquals("Ljava/lang/String;", field.getDesc());
        annotations = field.getAnnotations();
        assertEquals(1, annotations.size());
        AnnotationData annotation = annotations.get(0).getAnnotation();
        assertEquals("Lcom/google/gwt/dev/javac/typemodel/test/TestAnnotation;", annotation.getDesc());
        assertEquals("field", annotation.getValues().get("value"));
        assertEquals(0, cd.getInterfaceInternalNames().length);
        annotations = cd.getAnnotations();
        assertEquals(1, annotations.size());
        annotation = annotations.get(0).getAnnotation();
        assertEquals("Lcom/google/gwt/dev/javac/typemodel/test/PrimitiveValuesAnnotation;", annotation.getDesc());
        assertEquals(Byte.valueOf((byte) 42), annotation.getValues().get("b"));
        assertEquals(42, annotation.getValues().get("i"));
        assertEquals("java/lang/Object", cd.getSuperInternalName());
        assertEquals("CollectClassDataTest.Two", cd.getNestedSourceName());

        List<CollectMethodData> methods = cd.getMethods();
        assertEquals(3, methods.size());
        // TODO(jat): Is it safe to assume the order?
        CollectMethodData method = methods.get(0);
        Type[] argTypes = method.getArgTypes();
        String[] argNames = method.getArgNames();
        assertEquals("<init>", method.getName());
        assertEquals(1, argTypes.length);
        assertEquals(1, argNames.length);
        assertEquals(1, method.getArgAnnotations().length);
        assertEquals(0, method.getAnnotations().size());
        assertEquals(0, method.getExceptions().length);

        method = methods.get(1);
        argTypes = method.getArgTypes();
        argNames = method.getArgNames();
        assertEquals("foo", method.getName());
        assertEquals(1, argTypes.length);
        assertEquals("int", argTypes[0].getClassName());
        assertEquals(1, argNames.length);
        assertEquals("a", argNames[0]);
        assertEquals(1, method.getArgAnnotations().length);
        assertEquals(0, method.getArgAnnotations()[0].size());
        assertEquals(1, method.getAnnotations().size());
        assertEquals(1, method.getExceptions().length);

        method = methods.get(2);
        argTypes = method.getArgTypes();
        argNames = method.getArgNames();
        assertEquals("<init>", method.getName());
        assertEquals(2, argTypes.length);
        assertEquals("int", argTypes[0].getClassName());
        assertEquals("java.lang.String", argTypes[1].getClassName());
        assertEquals(2, argNames.length);
        assertEquals("a", argNames[0]);
        assertEquals("b", argNames[1]);
        assertEquals(2, method.getArgAnnotations().length);
        assertEquals(0, method.getArgAnnotations()[0].size());
        assertEquals(0, method.getArgAnnotations()[1].size());
        assertEquals(0, method.getAnnotations().size());
        assertEquals(0, method.getExceptions().length);
    }

    public void testTwoInner() {
        CollectClassData cd = collect(Two.TwoInner.class);
        // Don't check for super bit, as it will depend on the JDK used to compile.
        assertEquals(Opcodes.ACC_PUBLIC, cd.getAccess() & ~Opcodes.ACC_SUPER);
        assertEquals(ClassType.Inner, cd.getClassType());
        assertEquals("CollectClassDataTest.Two.TwoInner", cd.getNestedSourceName());
    }

    public void testPseudoInner() {
        CollectClassData cd = collect(Pseudo$Inner.class);
        assertEquals("CollectClassDataTest.Pseudo$Inner", cd.getNestedSourceName());
    }

    public void testPseudoInnerDeepest() {
        CollectClassData cd = collect(Deepest.class);
        assertEquals("CollectClassDataTest.Pseudo$Inner.Deepest", cd.getNestedSourceName());
    }

    public void testLocal() {
        CollectClassData cd = collect(Three.class.getName() + "$2Foo");
        // Don't check for super bit, as it will depend on the JDK used to compile.
        assertEquals(0, cd.getAccess() & ~Opcodes.ACC_SUPER);
        assertEquals(ClassType.Local, cd.getClassType());
        assertEquals("methodWithLocal", cd.getEnclosingMethodName());
    }

    public void testLocalStatic() {
        CollectClassData cd = collect(Three.class.getName() + "$1Foo");
        // Don't check for super bit, as it will depend on the JDK used to compile.
        assertEquals(0, cd.getAccess() & ~Opcodes.ACC_SUPER);
        assertEquals(ClassType.Local, cd.getClassType());
        assertEquals("methodWithLocalStatic", cd.getEnclosingMethodName());
        assertEquals(null, cd.getNestedSourceName());
    }

    // See http://code.google.com/p/google-web-toolkit/issues/detail?id=6591
    // Argument names were incorrect in the presence of long/double args
    public void testLongDoubleArgs() {
        CollectClassData cd = collect(LongDoubleArgs.class);
        assertEquals("CollectClassDataTest.LongDoubleArgs", cd.getNestedSourceName());
        List<CollectMethodData> methods = cd.getMethods();
        assertEquals(2, methods.size());
        CollectMethodData method = methods.get(0);
        Type[] argTypes = method.getArgTypes();
        String[] argNames = method.getArgNames();
        assertEquals("<init>", method.getName());
        assertEquals("x", argNames[0]);
        assertEquals("y", argNames[1]);
        assertEquals("z", argNames[2]);
        assertEquals("o", argNames[3]);
        assertEquals("I", argTypes[0].toString());
        assertEquals("J", argTypes[1].toString());
        assertEquals("D", argTypes[2].toString());
        assertEquals("Ljava/lang/Object;", argTypes[3].toString());

        method = methods.get(1);
        argTypes = method.getArgTypes();
        argNames = method.getArgNames();
        assertEquals("longDoubleMethod", method.getName());
        assertEquals("xx", argNames[0]);
        assertEquals("yy", argNames[1]);
        assertEquals("zz", argNames[2]);
        assertEquals("s", argNames[3]);
        assertEquals("I", argTypes[0].toString());
        assertEquals("J", argTypes[1].toString());
        assertEquals("D", argTypes[2].toString());
        assertEquals("Ljava/lang/String;", argTypes[3].toString());
    }

    private CollectClassData collect(Class<?> clazz) {
        return collect(clazz.getName());
    }

    private CollectClassData collect(String className) {
        byte[] bytes = getClassBytes(className);
        assertNotNull("Couldn't load bytes for " + className, bytes);
        CollectClassData cv = new CollectClassData();
        ClassReader reader = new ClassReader(bytes);
        reader.accept(cv, 0);
        return cv;
    }
}