| /* |
| * 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.typemodel.test.PrimitiveValuesAnnotation; |
| import com.google.gwt.dev.javac.typemodel.test.TestAnnotation; |
| import com.google.gwt.dev.asm.AnnotationVisitor; |
| import com.google.gwt.dev.asm.ClassReader; |
| import com.google.gwt.dev.asm.Opcodes; |
| import com.google.gwt.dev.asm.Type; |
| import com.google.gwt.dev.asm.commons.EmptyVisitor; |
| import com.google.gwt.dev.javac.asm.CollectAnnotationData.AnnotationData; |
| import com.google.gwt.dev.javac.asm.CollectClassData.ClassType; |
| |
| import java.util.List; |
| |
| /** |
| * Tests for {@link CollectClassData}. |
| */ |
| public class CollectClassDataTest extends AsmTestCase { |
| |
| 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); |
| } |
| } |
| |
| @PrimitiveValuesAnnotation(b = 42, i = 42) |
| protected static class Two { |
| |
| 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()); |
| } |
| |
| 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.getInterfaces().length); |
| assertEquals(0, cd.getAnnotations().size()); |
| assertEquals("com/google/gwt/dev/asm/commons/EmptyVisitor", |
| cd.getSuperName()); |
| |
| 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()); |
| } |
| |
| 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_PUBLIC | 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.getInterfaces().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.getSuperName()); |
| |
| 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()); |
| } |
| |
| 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.getOuterMethodName()); |
| } |
| |
| 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.getOuterMethodName()); |
| } |
| |
| 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; |
| } |
| } |