Author: j...@google.com Date: Wed Jul 1 08:34:40 2009 New Revision: 5656 Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/CollectReferencesVisitorTest.java Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectClassData.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectReferencesVisitor.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/AsmTestCase.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/CollectClassDataTest.java
Log: Add ASM visitor tests. Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectClassData.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectClassData.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectClassData.java Wed Jul 1 08:34:40 2009 @@ -20,7 +20,6 @@ import com.google.gwt.dev.asm.MethodVisitor; import com.google.gwt.dev.asm.Opcodes; import com.google.gwt.dev.asm.commons.EmptyVisitor; -import com.google.gwt.dev.resource.Resource; import com.google.gwt.dev.util.Name; import java.util.ArrayList; @@ -134,7 +133,9 @@ private List<CollectAnnotationData> annotations = new ArrayList<CollectAnnotationData>(); private String source = null; - private List<Resource> innerClasses = new ArrayList<Resource>(); + + // TODO(jat): do we need to collect inner classes? +// private List<Resource> innerClasses = new ArrayList<Resource>(); // internal name private String name; @@ -194,12 +195,12 @@ return fields; } - /** - * @return the innerClasses - */ - public List<Resource> getInnerClasses() { - return innerClasses; - } +// /** +// * @return the innerClasses +// */ +// public List<Resource> getInnerClasses() { +// return innerClasses; +// } /** * @return the interfaces Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectReferencesVisitor.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectReferencesVisitor.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/CollectReferencesVisitor.java Wed Jul 1 08:34:40 2009 @@ -15,10 +15,13 @@ */ package com.google.gwt.dev.javac.asm; +import com.google.gwt.dev.asm.AnnotationVisitor; import com.google.gwt.dev.asm.FieldVisitor; import com.google.gwt.dev.asm.MethodVisitor; import com.google.gwt.dev.asm.Type; import com.google.gwt.dev.asm.commons.EmptyVisitor; +import com.google.gwt.dev.asm.signature.SignatureReader; +import com.google.gwt.dev.asm.signature.SignatureVisitor; import java.util.HashSet; import java.util.Set; @@ -27,22 +30,80 @@ * Collect all the types which are referenced by a particular class. */ public class CollectReferencesVisitor extends EmptyVisitor { - // TODO(jat): support annotation types, types in generic signatures - private static final EmptyVisitor emptyVisitor = new 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 implements SignatureVisitor { + public SignatureVisitor visitArrayType() { + return this; + } + + public void visitBaseType(char descriptor) { + } + + public SignatureVisitor visitClassBound() { + return this; + } + + public void visitClassType(String name) { + referencedTypes.add(name); + } + + public void visitEnd() { + } + + public SignatureVisitor visitExceptionType() { + return this; + } + + public void visitFormalTypeParameter(String name) { + } + + public void visitInnerClassType(String name) { + } + + public SignatureVisitor visitInterface() { + return this; + } + + public SignatureVisitor visitInterfaceBound() { + return this; + } + + public SignatureVisitor visitParameterType() { + return this; + } + + public SignatureVisitor visitReturnType() { + return this; + } + + public SignatureVisitor visitSuperclass() { + return this; + } + + public void visitTypeArgument() { + } + + public SignatureVisitor visitTypeArgument(char wildcard) { + return this; + } + + public void visitTypeVariable(String name) { + } + } + // internal names - private Set<String> referencedTypes = new HashSet<String>(); + protected Set<String> referencedTypes = new HashSet<String>(); public Set<String> getReferencedTypes() { return referencedTypes; } - /** - * @param name internal name of the class - * @param superName internal name of the super class - * @param interfaces array of internal names of implemented interfaces - */ @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { @@ -52,13 +113,28 @@ referencedTypes.add(intf); } } + collectTypesFromClassSignature(signature); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + addTypeIfClass(desc); + // we don't use visitEnd, so we can just use ourselves for nested visitors + return this; + } + + @Override + public void visitEnum(String name, String desc, String value) { + addTypeIfClass(desc); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - addTypeIfClass(Type.getType(desc)); - return emptyVisitor; + addTypeIfClass(desc); + collectTypesFromFieldSignature(signature); + // we don't use visitEnd, so we can just use ourselves for nested visitors + return this; } /** @@ -80,8 +156,10 @@ for (Type type : Type.getArgumentTypes(desc)) { addTypeIfClass(type); } - addTypeIfClass(Type.getReturnType(desc)); - return emptyVisitor; + addTypeIfClass(desc); + collectTypesFromClassSignature(signature); + // we don't use visitEnd, so we can just use ourselves for nested visitors + return this; } /** @@ -92,9 +170,29 @@ referencedTypes.add(owner); } - private void addTypeIfClass(Type type) { + protected void addTypeIfClass(String desc) { + addTypeIfClass(Type.getReturnType(desc)); + } + + protected void addTypeIfClass(Type type) { if (type.getSort() == Type.OBJECT) { referencedTypes.add(type.getInternalName()); } } -} \ No newline at end of file + + 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()); + } +} Modified: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/AsmTestCase.java ============================================================================== --- changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/AsmTestCase.java (original) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/AsmTestCase.java Wed Jul 1 08:34:40 2009 @@ -1,3 +1,18 @@ +/* + * 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.util.Util; @@ -6,6 +21,9 @@ import java.io.InputStream; +/** + * Base class for ASM unit tests that defines some useful methods. + */ public abstract class AsmTestCase extends TestCase { private static final ClassLoader CLASSLOADER = CollectClassDataTest.class.getClassLoader(); @@ -18,14 +36,29 @@ super(name); } + /** + * Read the bytes of a class. + * + * @param clazz class literal of the class to read + * @return bytes from class file or null if not found + */ protected byte[] getClassBytes(Class<?> clazz) { - byte[] bytes; + return getClassBytes(clazz.getName()); + } + + + /** + * Read the bytes of a class. + * + * @param className binary name (ie com.Foo$Bar) of the class to read + * @return bytes from class file or null if not found + */ + protected byte[] getClassBytes(String className) { InputStream str = CLASSLOADER.getResourceAsStream( - clazz.getName().replace('.', '/') + ".class"); + className.replace('.', '/') + ".class"); if (str == null) { return null; } return Util.readStreamAsBytes(str); } - -} \ No newline at end of file +} Modified: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/CollectClassDataTest.java ============================================================================== --- changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/CollectClassDataTest.java (original) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/CollectClassDataTest.java Wed Jul 1 08:34:40 2009 @@ -1,5 +1,5 @@ /* - * Copyright 2008 Google Inc. + * 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 @@ -25,7 +25,6 @@ import com.google.gwt.dev.javac.asm.CollectAnnotationData.AnnotationData; import com.google.gwt.dev.javac.asm.CollectClassData.ClassType; - import java.util.List; /** @@ -33,11 +32,16 @@ */ public class CollectClassDataTest extends AsmTestCase { - @SuppressWarnings("unused") 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); } } @@ -45,6 +49,9 @@ @PrimitiveValuesAnnotation(b = 42, i = 42) protected static class Two { + public class TwoInner { + } + private String field; @TestAnnotation("field") @@ -60,11 +67,22 @@ } public Two(int a, String b) { + new TwoInner(); field = b; annotatedField = field; } } + public void testAnonymous() { + CollectClassData cd = collect(One.class.getName() + "$1"); + // 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.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. @@ -72,9 +90,7 @@ cd.getAccess() & ~Opcodes.ACC_SUPER); assertEquals(ClassType.Nested, cd.getClassType()); assertEquals(0, cd.getFields().size()); - assertEquals(0, cd.getInnerClasses().size()); assertEquals(0, cd.getInterfaces().length); - // Note that @SuppressWarnings is a source-only annotation assertEquals(0, cd.getAnnotations().size()); assertEquals("com/google/gwt/dev/asm/commons/EmptyVisitor", cd.getSuperName()); @@ -110,6 +126,13 @@ 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. @@ -132,7 +155,6 @@ assertEquals("Lcom/google/gwt/core/ext/typeinfo/test/TestAnnotation;", annotation.getDesc()); assertEquals("field", annotation.getValues().get("value")); - assertEquals(0, cd.getInnerClasses().size()); assertEquals(0, cd.getInterfaces().length); annotations = cd.getAnnotations(); assertEquals(1, annotations.size()); @@ -187,9 +209,20 @@ 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()); + } + private CollectClassData collect(Class<?> clazz) { - byte[] bytes = getClassBytes(clazz); - assertNotNull("Couldn't load bytes for " + clazz, bytes); + 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(bytes); ClassReader reader = new ClassReader(bytes); reader.accept(cv, 0); Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/CollectReferencesVisitorTest.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/CollectReferencesVisitorTest.java Wed Jul 1 08:34:40 2009 @@ -0,0 +1,94 @@ +/* + * 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.core.ext.typeinfo.test.TestAnnotation; +import com.google.gwt.dev.asm.ClassReader; +import com.google.gwt.dev.util.Name.BinaryName; + +import java.util.Map; +import java.util.Set; + +/** + * Tests for {...@link CollectClassData}. + */ +public class CollectReferencesVisitorTest extends AsmTestCase { + + /** + * This class is empty, but it still has references to itself, its superclass + * (Object), and its enclosing class. + */ + public static class Empty { + } + + /** + * In addition to the visible types, this class has references to itself, its + * superclass (Object), and its enclosing class. + */ + public static class Full { + + protected Integer i; + protected String s; + + @TestAnnotation("foo") + public Map<Boolean, String> getMap() { + return null; + } + } + + public void testEmpty() { + CollectReferencesVisitor rv = collect(Empty.class); + Set<String> referencedTypes = rv.getReferencedTypes(); + assertEquals(3, referencedTypes.size()); + assertContainsInternalName(Object.class, referencedTypes); + assertContainsInternalName(CollectReferencesVisitorTest.class, + referencedTypes); + assertContainsInternalName(Empty.class, referencedTypes); + } + + public void testFull() { + CollectReferencesVisitor rv = collect(Full.class); + Set<String> referencedTypes = rv.getReferencedTypes(); + assertEquals(8, referencedTypes.size()); + assertContainsInternalName(Object.class, referencedTypes); + assertContainsInternalName(CollectReferencesVisitorTest.class, + referencedTypes); + assertContainsInternalName(Full.class, referencedTypes); + assertContainsInternalName(Map.class, referencedTypes); + assertContainsInternalName(Integer.class, referencedTypes); + assertContainsInternalName(String.class, referencedTypes); + assertContainsInternalName(Boolean.class, referencedTypes); + assertContainsInternalName(TestAnnotation.class, referencedTypes); + } + + private void assertContainsInternalName(Class<?> clazz, Set<String> set) { + String className = BinaryName.toInternalName(clazz.getName()); + assertTrue("Should contain " + className, set.contains(className)); + } + + private CollectReferencesVisitor collect(Class<?> clazz) { + return collect(clazz.getName()); + } + + private CollectReferencesVisitor collect(String className) { + byte[] bytes = getClassBytes(className); + assertNotNull("Couldn't load bytes for " + className, bytes); + CollectReferencesVisitor cv = new CollectReferencesVisitor(); + ClassReader reader = new ClassReader(bytes); + reader.accept(cv, 0); + return cv; + } +} --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---