Author: j...@google.com Date: Thu Jul 2 07:57:32 2009 New Revision: 5659 Added: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeParameterLookup.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveClassSignature.java changes/jat/ihm/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleMocks.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/ResolveGenericsTest.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestHandler.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestHandler1.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter0.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter1.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter2.java Removed: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveClassTypeVariables.java Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveParameterizedType.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/AsmTestCase.java
Log: Test for generics resolution. Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java Thu Jul 2 07:57:32 2009 @@ -48,7 +48,7 @@ import com.google.gwt.dev.javac.asm.CollectFieldData; import com.google.gwt.dev.javac.asm.CollectMethodData; import com.google.gwt.dev.javac.asm.CollectTypeParams; -import com.google.gwt.dev.javac.asm.ResolveClassTypeVariables; +import com.google.gwt.dev.javac.asm.ResolveClassSignature; import com.google.gwt.dev.javac.asm.ResolveMethodSignature; import com.google.gwt.dev.javac.asm.ResolveParameterizedType; import com.google.gwt.dev.javac.asm.CollectAnnotationData.AnnotationData; @@ -65,7 +65,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -77,51 +76,8 @@ public class TypeOracleMediator { /** - * Handles lookup of type parameters, handling a scope stack. + * Pairs of bits to convert from ASM Opcodes.* to Shared.* bitfields. */ - public static class TypeParameterLookup { - - private LinkedList<HashMap<String, JTypeParameter>> scopeStack = new LinkedList<HashMap<String, JTypeParameter>>(); - - public JTypeParameter lookup(String name) { - for (HashMap<String, JTypeParameter> scope : scopeStack) { - if (scope.containsKey(name)) { - return scope.get(name); - } - } - return null; - } - - public void popScope() { - scopeStack.remove(); - } - - public void pushEnclosingScopes(JClassType type) { - if (type == null) { - return; - } - pushEnclosingScopes(type.getEnclosingType()); - JGenericType genericType = type.isGenericType(); - if (genericType != null) { - pushScope(genericType.getTypeParameters()); - } - } - - public void pushScope(JTypeParameter[] typeParams) { - // push empty scopes to keep pops in sync - scopeStack.addFirst(buildScope(typeParams)); - } - - private HashMap<String, JTypeParameter> buildScope( - JTypeParameter[] typeParams) { - HashMap<String, JTypeParameter> scope = new HashMap<String, JTypeParameter>(); - for (JTypeParameter typeParam : typeParams) { - scope.put(typeParam.getName(), typeParam); - } - return scope; - } - } - private static final int[] ASM_TO_SHARED_MODIFIERS = new int[] { Opcodes.ACC_PUBLIC, Shared.MOD_PUBLIC, Opcodes.ACC_PRIVATE, Shared.MOD_PRIVATE, @@ -172,13 +128,13 @@ } private static JTypeParameter[] collectTypeParams(String signature) { - // TODO(jat): more efficient when signature is null - List<JTypeParameter> params = new ArrayList<JTypeParameter>(); if (signature != null) { + List<JTypeParameter> params = new ArrayList<JTypeParameter>(); SignatureReader reader = new SignatureReader(signature); reader.accept(new CollectTypeParams(params)); + return params.toArray(new JTypeParameter[params.size()]); } - return params.toArray(new JTypeParameter[params.size()]); + return new JTypeParameter[0]; } private static <T> Class<? extends T> getClassLiteral(TreeLogger logger, @@ -583,6 +539,16 @@ } } + private boolean isPrivateEnumConstructor(JAbstractMethod method, + Type[] argTypes) { + return "<init>".equals(method.getName()) + && method.isPrivate() + && method.getEnclosingType().isEnum() != null + && argTypes.length >= 2 + && "Ljava/lang/String;".equals(argTypes[0].getDescriptor()) + && argTypes[1].getSort() == Type.INT; + } + /** * Map a bitset onto a different bitset. * @@ -739,7 +705,7 @@ } // TODO(jat): other checks? try { - // TODO(jat): can we use Class.forName here? + // TODO(jat): is it safe to use Class.forName here? return Class.forName(objType.getQualifiedBinaryName(), false, TypeOracleMediator.class.getClassLoader()); } catch (ClassNotFoundException e) { @@ -876,7 +842,7 @@ if (signature != null) { // If we have a signature, use it for superclass and interfaces SignatureReader reader = new SignatureReader(signature); - ResolveClassTypeVariables resolver = new ResolveClassTypeVariables( + ResolveClassSignature resolver = new ResolveClassSignature( typeOracle, binaryMapper, logger, type, typeParamLookup); reader.accept(resolver); resolver.finish(); @@ -1075,20 +1041,10 @@ method.setFakeArgNames(); } - // if (!resolveBoundsForTypeParameters(logger, type, method, methodData, - // typeParamLookup)) { - // return false; - // } - String signature = methodData.getSignature(); Type[] argTypes = methodData.getArgTypes(); String[] argNames = methodData.getArgNames(); - if ("<init>".equals(method.getName()) - && method.isPrivate() - && method.getEnclosingType().isEnum() != null - && argTypes.length >= 2 - && "Ljava/lang/String;".equals(argTypes[0].getDescriptor()) - && argTypes[1].getSort() == Type.INT) { + if (isPrivateEnumConstructor(method, argTypes)) { // Handle enum private constructors specially, by removing the two // hidden fields for the name and ordinal. Type[] newTypes = new Type[argTypes.length - 2]; @@ -1101,8 +1057,8 @@ if (signature != null) { // If we have a signature, use it for superclass and interfaces SignatureReader reader = new SignatureReader(signature); - ResolveMethodSignature resolver = new ResolveMethodSignature(this, logger, - method, typeParamLookup, hasReturnType, methodData, argTypes, + ResolveMethodSignature resolver = new ResolveMethodSignature(this, + logger, method, typeParamLookup, hasReturnType, methodData, argTypes, argNames); // TraceSignatureVisitor trace = new TraceSignatureVisitor( // methodData.getAccess()); Added: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeParameterLookup.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeParameterLookup.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,69 @@ +/* + * 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; + +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JGenericType; +import com.google.gwt.core.ext.typeinfo.JTypeParameter; + +import java.util.HashMap; +import java.util.LinkedList; + +/** + * Handles lookup of type parameters, using a scope stack. + */ +public class TypeParameterLookup { + + private LinkedList<HashMap<String, JTypeParameter>> scopeStack = new LinkedList<HashMap<String, JTypeParameter>>(); + + public JTypeParameter lookup(String name) { + for (HashMap<String, JTypeParameter> scope : scopeStack) { + if (scope.containsKey(name)) { + return scope.get(name); + } + } + return null; + } + + public void popScope() { + scopeStack.remove(); + } + + public void pushEnclosingScopes(JClassType type) { + if (type == null) { + return; + } + pushEnclosingScopes(type.getEnclosingType()); + JGenericType genericType = type.isGenericType(); + if (genericType != null) { + pushScope(genericType.getTypeParameters()); + } + } + + public void pushScope(JTypeParameter[] typeParams) { + // push empty scopes to keep pops in sync + scopeStack.addFirst(buildScope(typeParams)); + } + + private HashMap<String, JTypeParameter> buildScope( + JTypeParameter[] typeParams) { + HashMap<String, JTypeParameter> scope = new HashMap<String, JTypeParameter>(); + for (JTypeParameter typeParam : typeParams) { + scope.put(typeParam.getName(), typeParam); + } + return scope; + } +} \ No newline at end of file Added: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveClassSignature.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveClassSignature.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,129 @@ +/* + * 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.TreeLogger; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JRealClassType; +import com.google.gwt.core.ext.typeinfo.JType; +import com.google.gwt.core.ext.typeinfo.JTypeParameter; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.dev.asm.signature.SignatureVisitor; +import com.google.gwt.dev.javac.TypeParameterLookup; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Signature visitor that resolves all the type variables and their bounds for + * a given class. + */ +public class ResolveClassSignature extends EmptySignatureVisitor { + + private final TypeOracle typeOracle; + private final Map<String, JRealClassType> binaryMapper; + private final TreeLogger logger; + private final JRealClassType type; + private final TypeParameterLookup lookup; + + private JTypeParameter currentParam = null; + private ArrayList<JType[]> bounds = null; + private JType[] superClass = new JType[1]; + private List<JType[]> interfaces = new ArrayList<JType[]>(); + + public ResolveClassSignature(TypeOracle typeOracle, + Map<String, JRealClassType> binaryMapper, TreeLogger logger, + JRealClassType type, TypeParameterLookup lookup) { + this.typeOracle = typeOracle; + this.binaryMapper = binaryMapper; + this.logger = logger; + this.type = type; + this.lookup = lookup; + } + + public void finish() { + if (currentParam != null) { + int n = bounds.size(); + JClassType[] boundTypes = new JClassType[n]; + for (int i = 0; i < n; ++i) { + boundTypes[i] = (JClassType) bounds.get(i)[0]; + } + currentParam.setBounds(boundTypes); + currentParam = null; + // TODO(jat): remove after debugging phase + bounds = null; + } + if (superClass[0] != null) { + if (type.isInterface() != null) { + // The generic signature contains a superclass for interfaces, + // but TypeOracle doesn't like that -- verify that we were + // told Object is the superclass and ignore it. + assert superClass[0].equals(typeOracle.getJavaLangObject()); + } else { + type.setSuperclass((JClassType) superClass[0]); + } + superClass[0] = null; + } + for (JType[] intfRef : interfaces) { + if (intfRef[0] != null) { + type.addImplementedInterface((JClassType) intfRef[0]); + } + } + interfaces.clear(); + } + + @Override + public SignatureVisitor visitArrayType() { + assert false : "visitArrayType called on ResolveClassTypeVariables"; + return null; + } + + @Override + public SignatureVisitor visitClassBound() { + JType[] bound = new JType[1]; + bounds.add(bound); + return new ResolveParameterizedType(typeOracle, binaryMapper, logger, bound, lookup, null); + } + + @Override + public void visitFormalTypeParameter(String name) { + finish(); + currentParam = lookup.lookup(name); + bounds = new ArrayList<JType[]>(); + } + + @Override + public SignatureVisitor visitInterface() { + finish(); + JType[] intf = new JType[1]; + interfaces.add(intf); + return new ResolveParameterizedType(typeOracle, binaryMapper, logger, intf, lookup, null); + } + + @Override + public SignatureVisitor visitInterfaceBound() { + JType[] bound = new JType[1]; + bounds.add(bound); + return new ResolveParameterizedType(typeOracle, binaryMapper, logger, bound, lookup, null); + } + + @Override + public SignatureVisitor visitSuperclass() { + finish(); + return new ResolveParameterizedType(typeOracle, binaryMapper, logger, superClass, lookup, null); + } +} \ No newline at end of file Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveMethodSignature.java Thu Jul 2 07:57:32 2009 @@ -25,7 +25,7 @@ import com.google.gwt.dev.asm.Type; import com.google.gwt.dev.asm.signature.SignatureVisitor; import com.google.gwt.dev.javac.TypeOracleMediator; -import com.google.gwt.dev.javac.TypeOracleMediator.TypeParameterLookup; +import com.google.gwt.dev.javac.TypeParameterLookup; import java.lang.annotation.Annotation; import java.util.ArrayList; Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveParameterizedType.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveParameterizedType.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/asm/ResolveParameterizedType.java Thu Jul 2 07:57:32 2009 @@ -27,7 +27,7 @@ import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.asm.signature.SignatureVisitor; -import com.google.gwt.dev.javac.TypeOracleMediator.TypeParameterLookup; +import com.google.gwt.dev.javac.TypeParameterLookup; import com.google.gwt.dev.util.Name; import java.util.ArrayList; @@ -55,11 +55,17 @@ /** * Resolve a parameterized type. * + * @param typeOracle + * @param binaryMapper + * @param logger * @param returnTypeRef "pointer" to return location, ie. 1-element array + * @param lookup + * @param enclosingClass */ - public ResolveParameterizedType(TypeOracle typeOracle, Map<String, JRealClassType> binaryMapper, - TreeLogger logger, JType[] returnTypeRef, - TypeParameterLookup lookup, JClassType enclosingClass) { + public ResolveParameterizedType(TypeOracle typeOracle, + Map<String, JRealClassType> binaryMapper, TreeLogger logger, + JType[] returnTypeRef, TypeParameterLookup lookup, + JClassType enclosingClass) { this(typeOracle, binaryMapper, logger, returnTypeRef, lookup, enclosingClass, '='); } Added: changes/jat/ihm/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleMocks.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleMocks.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,104 @@ +/* + * 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.core.ext.typeinfo; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.dev.javac.CompilationUnit; +import com.google.gwt.dev.javac.MockCompilationUnit; +import com.google.gwt.dev.javac.TypeOracleMediator; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; + +import java.util.ArrayList; +import java.util.List; + +/** + * Contains mocks of the base JRE classes for tests as compilation units. + */ +public class TypeOracleMocks { + + /** + * A minimal TypeOracle mock that adds java.lang.Object and exposes + * the addNewType hook to callers. + */ + public static class BareTypeOracle extends TypeOracle { + + public BareTypeOracle() { + JPackage javaLang = getOrCreatePackage("java.lang"); + JRealClassType javaLangObject = new JRealClassType(this, javaLang, + null, false, "Object", false); + addNewType(javaLangObject); + } + + // Increases visibility so tests in other packages can hook this. + @Override + protected void addNewType(JRealClassType newType) { + super.addNewType(newType); + } + } + + private TreeLogger logger; + private TypeOracleMediator mediator; + + public TypeOracleMocks() { + mediator = new TypeOracleMediator(); + if (false) { + logger = new PrintWriterTreeLogger(); + } else { + logger = TreeLogger.NULL; + } + } + + public void addMock(String pkg, String name, String src) { + List<CompilationUnit> units = new ArrayList<CompilationUnit>(); + units.add(buildMockForClass(pkg, name, src)); + mediator.addNewUnits(logger, units); + } + + public void addJreMocks() { + List<CompilationUnit> units = new ArrayList<CompilationUnit>(); + units.add(buildMockForClass("java.lang", "Class", null)); + units.add(buildMockForClass("java.lang", "Object", null)); + units.add(buildMockForClass("java.lang", "Throwable", null)); + units.add(buildMockForClass("java.util", "Map", + "public interface Map<K, V> {" + + " interface Entry<K, V> {" + + " K getKey();" + + " V getValue();" + + " }" + + " boolean contains(K key);" + + " V put(K key, V value);" + + " V get(K key);" + )); + mediator.addNewUnits(logger, units); + } + + public TypeOracleMediator getMediator() { + return mediator; + } + + public TypeOracle getTypeOracle() { + return mediator.getTypeOracle(); + } + + private CompilationUnit buildMockForClass(String pkg, String name, + String src) { + if (src == null) { + src = "public class " + name + " { }"; + } + src = "package " + pkg + ";" + src; + return new MockCompilationUnit(name, src); + } +} Modified: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java ============================================================================== --- changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java (original) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java Thu Jul 2 07:57:32 2009 @@ -30,6 +30,7 @@ this.source = source; } + @Override public String getDisplayLocation() { return "/mock/" + getTypeName(); } @@ -45,10 +46,12 @@ return source; } + @Override public String getTypeName() { return typeName; } + @Override public boolean isGenerated() { return true; } 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 Thu Jul 2 07:57:32 2009 @@ -46,7 +46,6 @@ return getClassBytes(clazz.getName()); } - /** * Read the bytes of a class. * @@ -60,5 +59,30 @@ return null; } return Util.readStreamAsBytes(str); + } + + /** + * Reads the source for a class. + * + * @param clazz class literal of the class to read + * @return source from .java file or null if not found + */ + protected String getClassSource(Class<?> clazz) { + return getClassSource(clazz.getName()); + } + + /** + * Reads the source for a class. + * + * @param className binary name (ie com.Foo$Bar) of the class to read + * @return source from .java file or null if not found + */ + protected String getClassSource(String className) { + InputStream str = CLASSLOADER.getResourceAsStream( + className.replace('.', '/') + ".java"); + if (str == null) { + return null; + } + return Util.readStreamAsString(str); } } Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/ResolveGenericsTest.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/ResolveGenericsTest.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,354 @@ +/* + * 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.TreeLogger; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JGenericType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JPackage; +import com.google.gwt.core.ext.typeinfo.JParameter; +import com.google.gwt.core.ext.typeinfo.JParameterizedType; +import com.google.gwt.core.ext.typeinfo.JPrimitiveType; +import com.google.gwt.core.ext.typeinfo.JRealClassType; +import com.google.gwt.core.ext.typeinfo.JType; +import com.google.gwt.core.ext.typeinfo.JTypeParameter; +import com.google.gwt.core.ext.typeinfo.JWildcardType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.core.ext.typeinfo.JWildcardType.BoundType; +import com.google.gwt.core.ext.typeinfo.TypeOracleMocks.BareTypeOracle; +import com.google.gwt.dev.asm.Opcodes; +import com.google.gwt.dev.asm.Type; +import com.google.gwt.dev.asm.signature.SignatureReader; +import com.google.gwt.dev.javac.TypeOracleMediator; +import com.google.gwt.dev.javac.TypeParameterLookup; +import com.google.gwt.dev.javac.asm.CollectClassData.ClassType; +import com.google.gwt.dev.util.log.AbstractTreeLogger; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.TypeVariable; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Tests for {...@link ResolveClassSignature} and + * {...@link ResolveMethodSignature}. + */ +public class ResolveGenericsTest extends AsmTestCase { + + public static class FailErrorTreeLogger extends AbstractTreeLogger { + @Override + protected AbstractTreeLogger doBranch() { + // TODO(jat): Auto-generated method stub + return null; + } + + @Override + protected void doCommitBranch(AbstractTreeLogger childBeingCommitted, + com.google.gwt.core.ext.TreeLogger.Type type, String msg, + Throwable caught, HelpInfo helpInfo) { + if (type == TreeLogger.ERROR) { + fail(msg); + } + } + + @Override + protected void doLog(int indexOfLogEntryWithinParentLogger, + com.google.gwt.core.ext.TreeLogger.Type type, String msg, + Throwable caught, HelpInfo helpInfo) { + if (type == TreeLogger.ERROR) { + fail(msg); + } + } + } + + /** + * An extension of JMethod which keeps the reflected Method around. + */ + public static class ReflectedMethod extends JMethod { + private Method method; + + public ReflectedMethod(JClassType type, String methodName, + Map<Class<? extends Annotation>, Annotation> annotations, + JTypeParameter[] typeParams, Method method) { + super(type, methodName, annotations, typeParams); + this.method = method; + } + + public Method getMethod() { + return method; + } + } + + public static class ResolverMockTypeOracle extends BareTypeOracle { + + private Map<String, JRealClassType> binaryMapper; + + public Map<String, JRealClassType> getBinaryMapper() { + ensureBinaryMapper(); + return binaryMapper; + } + + @Override + public JParameterizedType getParameterizedType(JGenericType genericType, + JClassType enclosingType, JClassType[] typeArgs) { + // TODO(jat): Auto-generated method stub + return super.getParameterizedType(genericType, enclosingType, typeArgs); + } + + @Override + public JWildcardType getWildcardType(BoundType boundType, + JClassType typeBound) { + // TODO(jat): Auto-generated method stub + return super.getWildcardType(boundType, typeBound); + } + + @Override + protected void addNewType(JRealClassType type) { + super.addNewType(type); + String name = type.getQualifiedBinaryName().replace('.', '/'); + ensureBinaryMapper(); + binaryMapper.put(name, type); + } + + private void ensureBinaryMapper() { + if (binaryMapper == null) { + binaryMapper = new HashMap<String, JRealClassType>(); + } + } + } + + private static final TreeLogger failTreeLogger = new FailErrorTreeLogger(); + + private static final String OUTER_CLASS_SIG + = "<H:Lcom/google/gwt/dev/javac/asm/TestHandler;>Ljava/lang/Object;"; + private static final String OUTER_METHOD_SIG = "(TH;)V"; + + private static final String OUTER1_CLASS_SIG + = "<V:Ljava/lang/Object;>Lcom/google/gwt/dev/javac/asm/TestOuter0<" + + "Lcom/google/gwt/dev/javac/asm/TestHandler1<TV;>;>;"; + private static final String OUTER1_METHOD_SIG + = "(Lcom/google/gwt/dev/javac/asm/TestHandler1<TV;>;)V"; + + private static final String OUTER2_CLASS_SIG + = "Lcom/google/gwt/dev/javac/asm/TestOuter1<Ljava/lang/String;>;"; + private static final String OUTER2_METHOD_SIG + = "(Lcom/google/gwt/dev/javac/asm/TestHandler1<Ljava/lang/String;>;)V"; + + private ResolverMockTypeOracle oracle; + + @SuppressWarnings("unused") + private JRealClassType testHandler; + @SuppressWarnings("unused") + private JRealClassType testHandler1; + + private JRealClassType testOuter0; + private JRealClassType testOuter1; + private JRealClassType testOuter2; + + private ReflectedMethod testOuter0dispatch; + private ReflectedMethod testOuter1dispatch; + private ReflectedMethod testOuter2dispatch; + + @SuppressWarnings("unused") + private JRealClassType testType; + + @Override + public void setUp() { + oracle = new ResolverMockTypeOracle(); + testHandler = createUnresolvedClass(TestHandler.class, null); + testHandler1 = createUnresolvedClass(TestHandler1.class, null); + testOuter0 = createUnresolvedClass(TestOuter0.class, null); + testType = createUnresolvedClass(TestOuter0.Type.class, testOuter0); + testOuter1 = createUnresolvedClass(TestOuter1.class, null); + testOuter2 = createUnresolvedClass(TestOuter2.class, null); + testOuter0dispatch = createUnresolvedMethod(testOuter0, TestOuter0.class, + "dispatch", TestHandler.class); + testOuter1dispatch = createUnresolvedMethod(testOuter1, TestOuter1.class, + "dispatch", TestHandler.class); + testOuter2dispatch = createUnresolvedMethod(testOuter2, TestOuter2.class, + "dispatch", TestHandler.class); + } + + public void testOuter0Class() { + resolveClassSignature(testOuter0, OUTER_CLASS_SIG); + assertNotNull(testOuter0.getSuperclass()); + // TODO(jat): additional checks? + } + + public void testOuter0Method() { + resolveMethodSignature(testOuter0dispatch, OUTER_METHOD_SIG); + // TODO(jat): meaningful tests besides no errors? + } + + public void testOuter1Class() { + resolveClassSignature(testOuter1, OUTER1_CLASS_SIG); + JClassType superClass = testOuter1.getSuperclass(); + assertNotNull(superClass); + assertNotNull(superClass.isParameterized()); + // TODO(jat): additional checks? + } + + public void testOuter1Method() { + resolveMethodSignature(testOuter1dispatch, OUTER1_METHOD_SIG); + // TODO(jat): meaningful tests besides no errors? + } + + public void testOuter2Class() { + resolveClassSignature(testOuter2, OUTER2_CLASS_SIG); + JClassType superClass = testOuter2.getSuperclass(); + assertNotNull(superClass); + assertNotNull(superClass.isParameterized()); + // TODO(jat): additional checks? + } + + public void testOuter2Method() { + resolveMethodSignature(testOuter2dispatch, OUTER2_METHOD_SIG); + // TODO(jat): meaningful tests besides no errors? + } + + private JTypeParameter[] createTypeParams(TypeVariable<?>[] typeParams) { + int n = typeParams.length; + JTypeParameter[] params = new JTypeParameter[n]; + for (int i = 0; i < n; ++i) { + params[i] = new JTypeParameter(typeParams[i].getName(), i); + } + return params; + } + + private JRealClassType createUnresolvedClass(Class<?> clazz, + JRealClassType enclosingType) { + String pkgName = clazz.getPackage().getName(); + JPackage pkg = oracle.getOrCreatePackage(pkgName); + TypeVariable<?>[] typeParams = clazz.getTypeParameters(); + JRealClassType type; + int n = typeParams.length; + if (n == 0) { + type = new JRealClassType(oracle, pkg, enclosingType, + false, clazz.getSimpleName(), clazz.isInterface()); + } else { + JTypeParameter[] params = createTypeParams(typeParams); + type = new JGenericType(oracle, pkg, enclosingType, false, + clazz.getSimpleName(), clazz.isInterface(), params); + } + return type; + } + + private ReflectedMethod createUnresolvedMethod(JClassType type, Class<?> clazz, + String methodName, Class<?>... paramTypes) { + Method method = null; + try { + method = clazz.getMethod(methodName, paramTypes); + } catch (SecurityException e) { + fail("Exception " + e + " creating method " + methodName + " on " + clazz); + } catch (NoSuchMethodException e) { + fail("Exception " + e + " creating method " + methodName + " on " + clazz); + } + JTypeParameter[] typeParams = createTypeParams(method.getTypeParameters()); + Map<Class<? extends Annotation>, Annotation> emptyMap + = Collections.emptyMap(); + return new ReflectedMethod(type, methodName, emptyMap, typeParams, method); + } + + private Type getAsmType(JType type) { + JPrimitiveType primitiveType = type.isPrimitive(); + if (primitiveType != null) { + if (primitiveType == JPrimitiveType.BOOLEAN) { + return Type.BOOLEAN_TYPE; + } + if (primitiveType == JPrimitiveType.BYTE) { + return Type.BYTE_TYPE; + } + if (primitiveType == JPrimitiveType.CHAR) { + return Type.CHAR_TYPE; + } + if (primitiveType == JPrimitiveType.DOUBLE) { + return Type.DOUBLE_TYPE; + } + if (primitiveType == JPrimitiveType.FLOAT) { + return Type.FLOAT_TYPE; + } + if (primitiveType == JPrimitiveType.INT) { + return Type.INT_TYPE; + } + if (primitiveType == JPrimitiveType.LONG) { + return Type.LONG_TYPE; + } + if (primitiveType == JPrimitiveType.SHORT) { + return Type.SHORT_TYPE; + } + if (primitiveType == JPrimitiveType.VOID) { + return Type.VOID_TYPE; + } + fail("Unexpected primitive type " + primitiveType); + } + return Type.getObjectType(type.getQualifiedBinaryName().replace('.', '/')); + } + + private void resolveClassSignature(JRealClassType type, String signature) { + Map<String, JRealClassType> binaryMapper = oracle.getBinaryMapper(); + TypeParameterLookup lookup = new TypeParameterLookup(); + lookup.pushEnclosingScopes(type); + ResolveClassSignature resolver = new ResolveClassSignature(oracle, + binaryMapper, failTreeLogger, type, lookup); + new SignatureReader(signature).accept(resolver); + resolver.finish(); + } + + private void resolveMethodSignature(ReflectedMethod method, + String signature) { + TypeParameterLookup lookup = new TypeParameterLookup(); + lookup.pushEnclosingScopes(method.getEnclosingType()); + lookup.pushScope(method.getTypeParameters()); + TypeOracleMediator mediator = new TypeOracleMediator() { + @Override + public Map<String, JRealClassType> getBinaryMapper() { + return oracle.getBinaryMapper(); + } + + @Override + public TypeOracle getTypeOracle() { + return oracle; + } + + @Override + public boolean resolveAnnotations(TreeLogger logger, + List<CollectAnnotationData> annotations, + Map<Class<? extends Annotation>, Annotation> declaredAnnotations) { + return true; + } + }; + int access = Opcodes.ACC_PUBLIC; + String desc = Type.getMethodDescriptor(method.getMethod()); + CollectMethodData methodData = new CollectMethodData(ClassType.TopLevel, + access, method.getName(), desc, signature, null); + JParameter[] params = method.getParameters(); + int n = params.length; + Type[] argTypes = new Type[n]; + String[] argNames = new String[n]; + for (int i = 0; i < n; ++i) { + argNames[i] = "arg" + i; + argTypes[i] = getAsmType(params[i].getType()); + } + ResolveMethodSignature resolver = new ResolveMethodSignature(mediator, + failTreeLogger, method, lookup, true, methodData, argTypes, argNames); + new SignatureReader(signature).accept(resolver); + resolver.finish(); + } +} Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestHandler.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestHandler.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,19 @@ +/* + * Copyright 2008 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; + +public interface TestHandler { +} \ No newline at end of file Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestHandler1.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestHandler1.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,24 @@ +/* + * 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; + +/** + * Test class for generic signature validation. + * + * @param <V> + */ +public class TestHandler1<V> implements TestHandler { +} Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter0.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter0.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,25 @@ +/* + * 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; + +public abstract class TestOuter0<H extends TestHandler> { + public static class Type<H> { + public Type() { + } + } + + public abstract void dispatch(H handler); +} \ No newline at end of file Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter1.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter1.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,23 @@ +/* + * 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; + +public class TestOuter1<V> extends TestOuter0<TestHandler1<V>> { + + @Override + public void dispatch(TestHandler1<V> handler) { + } +} Added: changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter2.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/asm/TestOuter2.java Thu Jul 2 07:57:32 2009 @@ -0,0 +1,23 @@ +/* + * 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; + +public class TestOuter2 extends TestOuter1<String> { + + @Override + public void dispatch(TestHandler1<String> handler) { + } +} --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---