The attached patch finishes up the Java 1.5 support in the TypeOracle. The patch makes the following changes: * Implemented the functionality missing from the JDelegatingClassType subtypes. * Enabled erasure and type parameter substitution for JRawType and JParameterizedType respectively. This means that List<Interger> is a full blown JClassType where every reference to its type parameter has been replaced with Integer. * JParameterizedTypes and JWildcard types now have referential stability. * Added test cases for the new functionality. * Added support for enumerated types * Implemented a wildcard capture type scheme that allows us to reasonably determine the set of subtypes of a parameterized type since this is technically an unbounded set. For example, the subtypes List<Integer> could actually be parameterized types like MyList<? extends Serializable, Integer> and so on. * Fixes a bug in our Annotation proxy; we failed to implement the Annotation.annotationType() method. * Fixed a problem with annotations. Specifically, JLS3 9.7, single element array values do not need curly braces * Other minor issues with our JDT mapping Issues outstanding: * Subtype and assignability checks may still not deal with all of the corner cases. * The TypeOracle's refresh logic needs to be update to properly flush generics and parameterized types are out of date. Patch by: mmendez Review by: scottb (TBR) git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1523 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/AbstractMembers.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/AbstractMembers.java new file mode 100644 index 0000000..47fd220 --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/AbstractMembers.java
@@ -0,0 +1,269 @@ +/* + * Copyright 2007 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 java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +abstract class AbstractMembers { + + protected final JClassType classType; + private JMethod[] cachedOverridableMethods; + private final Map<String, JClassType> nestedTypes = new HashMap<String, JClassType>(); + + public AbstractMembers(JClassType classType) { + this.classType = classType; + } + + public JConstructor findConstructor(JType[] paramTypes) { + JConstructor[] ctors = getConstructors(); + for (int i = 0; i < ctors.length; i++) { + JConstructor candidate = ctors[i]; + if (candidate.hasParamTypes(paramTypes)) { + return candidate; + } + } + return null; + } + + public JField findField(String name) { + return doGetFields().get(name); + } + + public JMethod findMethod(String name, JType[] paramTypes) { + JMethod[] overloads = getOverloads(name); + for (int i = 0; i < overloads.length; i++) { + JMethod candidate = overloads[i]; + if (candidate.hasParamTypes(paramTypes)) { + return candidate; + } + } + return null; + } + + public JClassType findNestedType(String typeName) { + String[] parts = typeName.split("\\."); + return findNestedTypeImpl(parts, 0); + } + + public JConstructor getConstructor(JType[] paramTypes) + throws NotFoundException { + JConstructor result = findConstructor(paramTypes); + if (result == null) { + throw new NotFoundException(); + } + return result; + } + + public JConstructor[] getConstructors() { + return doGetConstructors().toArray(TypeOracle.NO_JCTORS); + } + + public JField getField(String name) { + JField field = findField(name); + assert (field != null); + return field; + } + + public JField[] getFields() { + return doGetFields().values().toArray(TypeOracle.NO_JFIELDS); + } + + public JMethod getMethod(String name, JType[] paramTypes) + throws NotFoundException { + JMethod result = findMethod(name, paramTypes); + if (result == null) { + throw new NotFoundException(); + } + return result; + } + + public JMethod[] getMethods() { + List<JMethod> resultMethods = new ArrayList<JMethod>(); + for (List<JMethod> overloads : doGetMethods().values()) { + resultMethods.addAll(overloads); + } + return resultMethods.toArray(TypeOracle.NO_JMETHODS); + } + + public JClassType getNestedType(String typeName) throws NotFoundException { + JClassType result = findNestedType(typeName); + if (result == null) { + throw new NotFoundException(); + } + return result; + } + + public JClassType[] getNestedTypes() { + return nestedTypes.values().toArray(TypeOracle.NO_JCLASSES); + } + + public JMethod[] getOverloads(String name) { + List<?> resultMethods = doGetMethods().get(name); + if (resultMethods != null) { + return resultMethods.toArray(TypeOracle.NO_JMETHODS); + } else { + return TypeOracle.NO_JMETHODS; + } + } + + public JMethod[] getOverridableMethods() { + if (cachedOverridableMethods == null) { + Map<String, JMethod> methodsBySignature = new TreeMap<String, JMethod>(); + getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); + if (classType.isClass() != null) { + getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); + } + int size = methodsBySignature.size(); + Collection<JMethod> leafMethods = methodsBySignature.values(); + cachedOverridableMethods = leafMethods.toArray(new JMethod[size]); + } + return cachedOverridableMethods; + } + + protected void addConstructor(JConstructor ctor) { + assert (!doGetConstructors().contains(ctor)); + doGetConstructors().add(ctor); + } + + protected void addField(JField field) { + Object existing = doGetFields().put(field.getName(), field); + assert (existing == null); + } + + protected void addMethod(JMethod method) { + String methodName = method.getName(); + Map<String, List<JMethod>> methods = doGetMethods(); + List<JMethod> overloads = methods.get(methodName); + if (overloads == null) { + overloads = new ArrayList<JMethod>(); + methods.put(methodName, overloads); + } + overloads.add(method); + } + + protected void addNestedType(JClassType type) { + nestedTypes.put(type.getSimpleSourceName(), type); + } + + protected abstract List<JConstructor> doGetConstructors(); + + protected abstract Map<String, JField> doGetFields(); + + protected abstract Map<String, List<JMethod>> doGetMethods(); + + protected JClassType findNestedTypeImpl(String[] typeName, int index) { + JClassType found = nestedTypes.get(typeName[index]); + if (found == null) { + return null; + } else if (index < typeName.length - 1) { + return found.findNestedTypeImpl(typeName, index + 1); + } else { + return found; + } + } + + protected void getOverridableMethodsOnSuperclassesAndThisClass( + Map<String, JMethod> methodsBySignature) { + assert (classType.isClass() != null); + + // Recurse first so that more derived methods will clobber less derived + // methods. + JClassType superClass = classType.getSuperclass(); + if (superClass != null) { + superClass.getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); + } + + JMethod[] declaredMethods = getMethods(); + for (int i = 0; i < declaredMethods.length; i++) { + JMethod method = declaredMethods[i]; + + // Ensure that this method is overridable. + if (method.isFinal() || method.isPrivate() || method.isStatic()) { + // We cannot override this method, so skip it. + continue; + } + + // We can override this method, so record it. + String sig = computeInternalSignature(method); + methodsBySignature.put(sig, method); + } + } + + /** + * Gets the methods declared in interfaces that this type extends. If this + * type is a class, its own methods are not added. If this type is an + * interface, its own methods are added. Used internally by + * {@link #getOverridableMethods()}. + * + * @param methodsBySignature + */ + protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface( + Map<String, JMethod> methodsBySignature) { + // Recurse first so that more derived methods will clobber less derived + // methods. + JClassType[] superIntfs = classType.getImplementedInterfaces(); + for (int i = 0; i < superIntfs.length; i++) { + JClassType superIntf = superIntfs[i]; + superIntf.getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); + } + + if (classType.isInterface() == null) { + // This is not an interface, so we're done after having visited its + // implemented interfaces. + return; + } + + JMethod[] declaredMethods = getMethods(); + for (int i = 0; i < declaredMethods.length; i++) { + JMethod method = declaredMethods[i]; + + String sig = computeInternalSignature(method); + JMethod existing = methodsBySignature.get(sig); + if (existing != null) { + JClassType existingType = existing.getEnclosingType(); + JClassType thisType = method.getEnclosingType(); + if (thisType.isAssignableFrom(existingType)) { + // The existing method is in a more-derived type, so don't replace it. + continue; + } + } + methodsBySignature.put(sig, method); + } + } + + protected JClassType getParentType() { + return classType; + } + + private String computeInternalSignature(JMethod method) { + StringBuffer sb = new StringBuffer(); + sb.setLength(0); + sb.append(method.getName()); + JParameter[] params = method.getParameters(); + for (int j = 0; j < params.length; j++) { + JParameter param = params[j]; + sb.append("/"); + sb.append(param.getType().getErasedType().getQualifiedSourceName()); + } + return sb.toString(); + } + +} \ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/Annotations.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/Annotations.java index 2d7631c..e90fa74 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/Annotations.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/Annotations.java
@@ -42,6 +42,23 @@ */ private Annotations parent; + Annotations() { + } + + Annotations(Annotations otherAnnotations) { + if (otherAnnotations != null) { + Annotation[] otherDeclaredAnnotations = otherAnnotations.getDeclaredAnnotations(); + for (Annotation otherDeclaredAnnotation : otherDeclaredAnnotations) { + addAnnotation(otherDeclaredAnnotation.annotationType(), + otherDeclaredAnnotation); + } + } + } + + Annotations(Map<Class<? extends Annotation>, Annotation> declaredAnnotations) { + this.declaredAnnotations.putAll(declaredAnnotations); + } + public void addAnnotations( Map<Class<? extends Annotation>, Annotation> annotations) { if (annotations != null) { @@ -92,11 +109,12 @@ lazyAnnotations = new HashMap<Class<? extends Annotation>, Annotation>(); parent.initializeAnnotations(); for (Entry<Class<? extends Annotation>, Annotation> entry : parent.lazyAnnotations.entrySet()) { - if (entry.getValue().annotationType().isAnnotationPresent(Inherited.class)) { + if (entry.getValue().annotationType().isAnnotationPresent( + Inherited.class)) { lazyAnnotations.put(entry.getKey(), entry.getValue()); } } - + lazyAnnotations.putAll(declaredAnnotations); } else { lazyAnnotations = declaredAnnotations;
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/DelegateMembers.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/DelegateMembers.java new file mode 100644 index 0000000..2502013 --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/DelegateMembers.java
@@ -0,0 +1,115 @@ +/* + * Copyright 2007 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 java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Class that initializes the different members of a + * {@link JDelegatingClassType} from its corresponding base type on demand. + */ +class DelegateMembers extends AbstractMembers { + private final JClassType baseType; + private List<JConstructor> lazyConstructors; + private Map<String, JField> lazyFields; + private Map<String, List<JMethod>> lazyMethods; + private final Substitution substitution; + + /** + */ + public DelegateMembers(JDelegatingClassType enclosingType, + JClassType baseType, Substitution substitution) { + super(enclosingType); + this.baseType = baseType; + this.substitution = substitution; + } + + @Override + protected List<JConstructor> doGetConstructors() { + if (lazyConstructors != null) { + /* + * Return if the constructors are being initialized or have been + * initialized. + */ + return lazyConstructors; + } + lazyConstructors = new ArrayList<JConstructor>(); + + JConstructor[] baseCtors = baseType.getConstructors(); + for (JConstructor baseCtor : baseCtors) { + JConstructor newCtor = new JConstructor(getParentType(), baseCtor); + initializeParams(baseCtor, newCtor); + addConstructor(newCtor); + } + + return lazyConstructors; + } + + @Override + protected Map<String, JField> doGetFields() { + if (lazyFields != null) { + /* + * Return if the fields are being initialized or have been + * initialized. + */ + return lazyFields; + } + lazyFields = new HashMap<String, JField>(); + + JField[] baseFields = baseType.getFields(); + for (JField baseField : baseFields) { + JField newField = new JField(getParentType(), baseField); + newField.setType(substitution.getSubstitution(baseField.getType())); + addField(newField); + } + + return lazyFields; + } + + @Override + protected Map<String, List<JMethod>> doGetMethods() { + if (lazyMethods != null) { + /* + * Return if the methods are being initialized or have been + * initialized. + */ + return lazyMethods; + } + lazyMethods = new HashMap<String, List<JMethod>>(); + + JMethod[] baseMethods = baseType.getMethods(); + for (JMethod baseMethod : baseMethods) { + JMethod newMethod = new JMethod(getParentType(), baseMethod); + initializeParams(baseMethod, newMethod); + newMethod.setReturnType(substitution.getSubstitution(baseMethod.getReturnType())); + addMethod(newMethod); + } + + return lazyMethods; + } + + private void initializeParams(JAbstractMethod srcMethod, + JAbstractMethod newMethod) { + for (JParameter srcParam : srcMethod.getParameters()) { + JParameter newParam = new JParameter(newMethod, srcParam); + newParam.setType(substitution.getSubstitution(srcParam.getType())); + newMethod.addParameter(newParam); + } + } +}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java index be5ebca..e7f8b98 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java
@@ -26,7 +26,7 @@ public abstract class JAbstractMethod implements HasAnnotations, HasMetaData, HasTypeParameters { - private final Annotations annotations = new Annotations(); + private final Annotations annotations; private int bodyEnd; @@ -59,9 +59,26 @@ this.declEnd = declEnd; this.bodyStart = bodyStart; this.bodyEnd = bodyEnd; + annotations = new Annotations(); annotations.addAnnotations(declaredAnnotations); } + /** + * @param enclosingType + * @param ctor + */ + JAbstractMethod(JAbstractMethod srcMethod) { + this.annotations = new Annotations(srcMethod.annotations); + this.bodyEnd = srcMethod.bodyEnd; + this.bodyStart = srcMethod.bodyStart; + this.declEnd = srcMethod.declEnd; + this.declStart = srcMethod.declStart; + this.isVarArgs = srcMethod.isVarArgs; + MetaData.copy(this, srcMethod.metaData); + this.modifierBits = srcMethod.modifierBits; + this.name = srcMethod.name; + } + public void addMetaData(String tagName, String[] values) { metaData.addMetaData(tagName, values); }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java index a206c4b..d2f3ba7 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
@@ -24,6 +24,7 @@ * Type representing a Java array. */ public class JArrayType extends JClassType { + private static final JArrayType[] NO_JARRAYS = new JArrayType[0]; private JType componentType; @@ -63,14 +64,12 @@ @Override public JField findField(String name) { - // TODO length return null; } @Override public JMethod findMethod(String name, JType[] paramTypes) { - // TODO Object - return null; + return getOracle().getJavaLangObject().findMethod(name, paramTypes); } @Override @@ -110,12 +109,12 @@ @Override public JConstructor getConstructor(JType[] paramTypes) throws NotFoundException { - return null; + throw new NotFoundException(); } @Override public JConstructor[] getConstructors() { - return null; + return TypeOracle.NO_JCTORS; } @Override @@ -130,19 +129,16 @@ @Override public JClassType getErasedType() { - // TODO array of component type - return this; + return getOracle().getArrayType(getComponentType().getErasedType()); } @Override public JField getField(String name) { - // TODO length return null; } @Override public JField[] getFields() { - // TODO length return TypeOracle.NO_JFIELDS; } @@ -151,10 +147,12 @@ return TypeOracle.NO_JCLASSES; } + @Override public String getJNISignature() { return "[" + componentType.getJNISignature(); } + @Override public JType getLeafType() { return componentType.getLeafType(); } @@ -172,20 +170,17 @@ @Override public JMethod getMethod(String name, JType[] paramTypes) throws NotFoundException { - // TODO Object - return null; + return getOracle().getJavaLangObject().getMethod(name, paramTypes); } @Override public JMethod[] getMethods() { - // TODO Object - return null; + return getOracle().getJavaLangObject().getMethods(); } @Override public String getName() { - // TODO Auto-generated method stub - return null; + return getSimpleSourceName(); } @Override @@ -205,26 +200,32 @@ @Override public JMethod[] getOverloads(String name) { - // TODO Object - return null; + return getOracle().getJavaLangObject().getOverloads(name); } @Override public JMethod[] getOverridableMethods() { - // TODO Object - return null; + return getOracle().getJavaLangObject().getOverridableMethods(); } @Override public JPackage getPackage() { - // TODO - return null; + JType leafType = getLeafType(); + if (leafType.isPrimitive() != null) { + // TODO: is there a default package? + return null; + } + + JClassType leafClass = (JClassType) leafType; + return leafClass.getPackage(); } + @Override public String getParameterizedQualifiedSourceName() { return getComponentType().getParameterizedQualifiedSourceName() + "[]"; } + @Override public String getQualifiedSourceName() { if (lazyQualifiedName == null) { lazyQualifiedName = getComponentType().getQualifiedSourceName() + "[]"; @@ -241,6 +242,7 @@ return 1; } + @Override public String getSimpleSourceName() { if (lazySimpleName == null) { lazySimpleName = getComponentType().getSimpleSourceName() + "[]"; @@ -249,21 +251,64 @@ } @Override - public JClassType[] getSubtypes() { - // TODO - return TypeOracle.NO_JCLASSES; + public JArrayType[] getSubtypes() { + if (getComponentType().isPrimitive() != null) { + return NO_JARRAYS; + } + + JClassType componentClass = (JClassType) getComponentType(); + JClassType[] componentSubtypes = componentClass.getSubtypes(); + JArrayType[] arraySubtypes = new JArrayType[componentSubtypes.length]; + for (int i = 0; i < componentSubtypes.length; ++i) { + arraySubtypes[i] = getOracle().getArrayType(componentSubtypes[i]); + } + + return arraySubtypes; } @Override public JClassType getSuperclass() { - // TODO Object? - return null; + JType compType = getComponentType(); + JClassType javaLangObject = getOracle().getJavaLangObject(); + if (compType.isPrimitive() != null) { + // Super of primitive[] is object + return javaLangObject; + } + + JArrayType arrayComponent = compType.isArray(); + if (arrayComponent != null) { + // Superclass of multi-dimensional array is superclass of component + return getOracle().getArrayType(arrayComponent.getSuperclass()); + } + + JClassType type = compType.isClassOrInterface(); + if (type == javaLangObject) { + // Superclass of Object[] is Object + return javaLangObject; + } + + JClassType superType = type.getSuperclass(); + if (superType == null) { + // Superclass of interface[] is Object[] + assert (type.isInterface() == null); + superType = javaLangObject; + } + + return getOracle().getArrayType(superType); } @Override public String getTypeHash() throws UnableToCompleteException { - // TODO - return null; + JType leafType = getLeafType(); + JClassType leafClassType = leafType.isClassOrInterface(); + if (leafClassType != null) { + return leafClassType.getTypeHash(); + } + + // Arrays of primitive types should have a stable hash + assert (leafType.isPrimitive() != null); + + return leafType.getQualifiedSourceName(); } @Override @@ -276,22 +321,51 @@ return false; } + @Override public JArrayType isArray() { return this; } @Override public boolean isAssignableFrom(JClassType possibleSubtype) { - // TODO - return false; + if (this == possibleSubtype) { + // type is assignable to itself + return true; + } + + JArrayType possibleSubtypeArray = possibleSubtype.isArray(); + if (possibleSubtypeArray == null) { + // possible subtype must be an array to be assignable + return false; + } + + JType thisComponentType = getComponentType(); + JType otherComponentType = possibleSubtypeArray.getComponentType(); + + if (thisComponentType.isPrimitive() != null + || otherComponentType.isPrimitive() != null) { + /* + * Since this was not equal to the possible subtype, we know that either + * the dimensions are off or the component types are off + */ + return false; + } + + assert (thisComponentType instanceof JClassType); + assert (otherComponentType instanceof JClassType); + + JClassType thisComponentClassType = (JClassType) thisComponentType; + JClassType otherComponentClassType = (JClassType) otherComponentType; + + return thisComponentClassType.isAssignableFrom(otherComponentClassType); } @Override public boolean isAssignableTo(JClassType possibleSupertype) { - // TODO - return false; + return possibleSupertype.isAssignableFrom(this); } + @Override public JClassType isClass() { // intentional null return null; @@ -303,10 +377,16 @@ } @Override + public JEnumType isEnum() { + return null; + } + + @Override public JGenericType isGenericType() { return null; } + @Override public JClassType isInterface() { // intentional null return null; @@ -322,11 +402,13 @@ return false; } + @Override public JParameterizedType isParameterized() { // intentional null return null; } + @Override public JPrimitiveType isPrimitive() { // intentional null return null; @@ -357,6 +439,11 @@ return true; } + @Override + public JWildcardType isWildcard() { + return null; + } + public void setLeafType(JType type) { JArrayType componentTypeIsArray = componentType.isArray(); if (componentTypeIsArray != null) { @@ -370,6 +457,7 @@ public void setSuperclass(JClassType type) { } + @Override public String toString() { return getQualifiedSourceName(); } @@ -388,13 +476,15 @@ @Override protected void getOverridableMethodsOnSuperclassesAndThisClass( Map<String, JMethod> methodsBySignature) { - // TODO Object + getOracle().getJavaLangObject().getOverridableMethodsOnSuperclassesAndThisClass( + methodsBySignature); } @Override protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface( Map<String, JMethod> methodsBySignature) { - // TODO Object + getOracle().getJavaLangObject().getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface( + methodsBySignature); } @Override @@ -435,6 +525,12 @@ } @Override + JArrayType getSubstitutedType(JParameterizedType parameterizedType) { + return oracle.getArrayType(getComponentType().getSubstitutedType( + parameterizedType)); + } + + @Override void notifySuperTypes() { }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JBound.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JBound.java index a59fc01..b9f6141 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JBound.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JBound.java
@@ -16,36 +16,81 @@ package com.google.gwt.core.ext.typeinfo; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** - * + * Represents a bound for a {@link JTypeParameter} or a {@link JWildcardType}. */ -public class JBound { +public abstract class JBound { + /** + * Types which make up this bound. + */ + private final List<JClassType> bounds = new ArrayList<JClassType>(); - private final JClassType firstBound; - private final List<JClassType> lowerBounds = new ArrayList<JClassType>(); - private final List<JClassType> upperBounds = new ArrayList<JClassType>(); - - public JBound(JClassType firstBound) { - this.firstBound = firstBound; + JBound(JClassType[] bounds) { + this.bounds.addAll(Arrays.asList(bounds)); } - public void addLowerBound(JClassType bound) { - lowerBounds.add(bound); - } - - public void addUpperBound(JClassType bound) { - upperBounds.add(bound); + public JClassType[] getBounds() { + return bounds.toArray(TypeOracle.NO_JCLASSES); } public JClassType getFirstBound() { - return firstBound; + assert (!bounds.isEmpty()); + + return bounds.get(0); } + public String getQualifiedSourceName() { + return toString(true); + } + + public String getSimpleSourceName() { + return toString(false); + } + + public abstract JLowerBound isLowerBound(); + + public abstract JUpperBound isUpperBound(); + @Override public String toString() { - return " extends " + firstBound.getParameterizedQualifiedSourceName(); + return getQualifiedSourceName(); } - + + abstract JClassType[] getSubtypes(); + + abstract boolean isAssignableFrom(JBound possibleSubWildcard); + + private String toString(boolean useQualifiedNames) { + StringBuffer sb = new StringBuffer(); + + if (isUpperBound() != null) { + sb.append(" extends "); + } else { + sb.append(" super "); + } + + boolean needsAmpersand = false; + for (JClassType bound : bounds) { + + if (needsAmpersand) { + sb.append(" & "); + } else { + needsAmpersand = true; + } + + String name; + if (useQualifiedNames) { + name = bound.getParameterizedQualifiedSourceName(); + } else { + name = bound.getSimpleSourceName(); + } + + sb.append(name); + } + + return sb.toString(); + } }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java index 276a179..359bc04 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
@@ -222,11 +222,13 @@ abstract JClassType findNestedTypeImpl(String[] typeName, int index); + @Override + abstract JClassType getSubstitutedType(JParameterizedType parameterizedType); + abstract void notifySuperTypes(); /** * Removes references to this instance from all of its super types. */ abstract void removeFromSupertypes(); - }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java index feb2044..504eaa3 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java
@@ -37,10 +37,17 @@ enclosingType.addConstructor(this); } + JConstructor(JClassType enclosingType, JConstructor ctor) { + super(ctor); + this.enclosingType = enclosingType; + } + + @Override public JClassType getEnclosingType() { return enclosingType; } + @Override public String getReadableDeclaration() { String[] names = TypeOracle.modifierBitsToNames(getModifierBits()); StringBuilder sb = new StringBuilder(); @@ -57,14 +64,17 @@ return sb.toString(); } + @Override public JConstructor isConstructor() { return this; } + @Override public JMethod isMethod() { return null; } + @Override public String toString() { return getReadableDeclaration(); }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java index 29df9df..e421658 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
@@ -26,7 +26,7 @@ */ abstract class JDelegatingClassType extends JClassType { - protected JClassType baseType; + private JClassType baseType; JDelegatingClassType() { } @@ -84,6 +84,10 @@ return baseType.getAnnotations(); } + public JClassType getBaseType() { + return baseType; + } + @Override public int getBodyEnd() { return baseType.getBodyEnd(); @@ -123,9 +127,12 @@ @Override public JClassType getEnclosingType() { + // TODO this can be wrong if the enclosing type is a parameterized type. For + // example, if a generic class has a non-static generic inner class. return baseType.getEnclosingType(); } + @Override public JClassType getErasedType() { return baseType.getErasedType(); } @@ -220,9 +227,6 @@ return baseType.getSuperclass(); } - /** - * TODO: What is this??? - */ @Override public String getTypeHash() throws UnableToCompleteException { return baseType.getTypeHash(); @@ -282,6 +286,11 @@ } @Override + public final JEnumType isEnum() { + return null; + } + + @Override public JClassType isInterface() { if (baseType.isInterface() != null) { return this; @@ -410,5 +419,4 @@ final void setBaseType(JClassType baseType) { this.baseType = baseType; } - }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumConstant.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumConstant.java new file mode 100644 index 0000000..cf35f88 --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumConstant.java
@@ -0,0 +1,47 @@ +/* + * Copyright 2007 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 java.lang.annotation.Annotation; +import java.util.Map; + +/** + * An enumeration constant declared in an enumerated type. + */ +public class JEnumConstant extends JField { + private final int ordinal; + + public JEnumConstant(JClassType enclosingType, String name, + Map<Class<? extends Annotation>, Annotation> declaredAnnotations, + int ordinal) { + super(enclosingType, name, declaredAnnotations); + this.ordinal = ordinal; + } + + /** + * Returns the ordinal value for this enumeration constant. + * + * @return ordinal value for this enumeration constant + */ + public int getOrdinal() { + return ordinal; + } + + @Override + public JEnumConstant isEnumConstant() { + return this; + } +}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumType.java new file mode 100644 index 0000000..c91f14b --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumType.java
@@ -0,0 +1,74 @@ +/* + * Copyright 2007 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 java.util.ArrayList; +import java.util.List; + +/** + * Type representing a Java enumerated type. + */ +public class JEnumType extends JRealClassType { + private JEnumConstant[] lazyEnumConstants; + + /** + * @param oracle + * @param cup + * @param declaringPackage + * @param enclosingType + * @param isLocalType + * @param name + * @param declStart + * @param declEnd + * @param bodyStart + * @param bodyEnd + * @param isInterface + */ + public JEnumType(TypeOracle oracle, CompilationUnitProvider cup, + JPackage declaringPackage, JClassType enclosingType, boolean isLocalType, + String name, int declStart, int declEnd, int bodyStart, int bodyEnd, + boolean isInterface) { + super(oracle, cup, declaringPackage, enclosingType, isLocalType, name, + declStart, declEnd, bodyStart, bodyEnd, isInterface); + } + + /** + * Returns the enumeration constants declared by this enumeration. + * + * @return enumeration constants declared by this enumeration + */ + public JEnumConstant[] getEnumConstants() { + if (lazyEnumConstants == null) { + List<JEnumConstant> enumConstants = new ArrayList<JEnumConstant>(); + for (JField field : getFields()) { + if (field.isEnumConstant() != null) { + enumConstants.add(field.isEnumConstant()); + } + } + + assert (!enumConstants.isEmpty()); + + lazyEnumConstants = enumConstants.toArray(new JEnumConstant[0]); + } + + return lazyEnumConstants; + } + + @Override + public JEnumType isEnum() { + return this; + } +}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JField.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JField.java index d8d920e..f7ce1d7 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JField.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JField.java
@@ -23,7 +23,7 @@ */ public class JField implements HasAnnotations, HasMetaData { - private final Annotations annotations = new Annotations(); + private final Annotations annotations; private final JClassType enclosingType; @@ -41,14 +41,24 @@ public JField(JClassType enclosingType, String name, Map<Class<? extends Annotation>, Annotation> declaredAnnotations) { + assert (enclosingType != null); this.enclosingType = enclosingType; this.name = name; - - assert (enclosingType != null); - enclosingType.addField(this); + this.enclosingType.addField(this); + annotations = new Annotations(); annotations.addAnnotations(declaredAnnotations); } + JField(JClassType enclosingType, JField srcField) { + this.annotations = new Annotations(srcField.annotations); + this.enclosingType = enclosingType; + this.modifierBits = srcField.modifierBits; + this.name = srcField.name; + this.type = srcField.type; + + MetaData.copy(this, srcField); + } + public void addMetaData(String tagName, String[] values) { metaData.addMetaData(tagName, values); } @@ -99,6 +109,10 @@ return 0 == (modifierBits & (TypeOracle.MOD_PUBLIC | TypeOracle.MOD_PRIVATE | TypeOracle.MOD_PROTECTED)); } + public JEnumConstant isEnumConstant() { + return null; + } + public boolean isFinal() { return 0 != (modifierBits & TypeOracle.MOD_FINAL); }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java index d5dda07..533f074 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java
@@ -41,7 +41,14 @@ @Override public String getParameterizedQualifiedSourceName() { StringBuffer sb = new StringBuffer(); - sb.append(getQualifiedSourceName()); + + if (getEnclosingType() != null) { + sb.append(getEnclosingType().getParameterizedQualifiedSourceName()); + sb.append("."); + sb.append(getSimpleSourceName()); + } else { + sb.append(getQualifiedSourceName()); + } sb.append('<'); boolean needComma = false; @@ -59,8 +66,9 @@ public JRawType getRawType() { if (lazyRawType == null) { - lazyRawType = new JRawType(this); + lazyRawType = new JRawType(this, getEnclosingType()); } + return lazyRawType; } @@ -69,21 +77,17 @@ } @Override - public boolean isDefaultInstantiable() { - /* - * By definition, you cannot instantiate a generic type, only a - * parameterized type or a raw type? - */ - return false; - } - - @Override public JGenericType isGenericType() { return this; } - protected boolean isDefaultInstantiableIfParameterized() { - return super.isDefaultInstantiable(); + @Override + public String toString() { + if (isInterface() != null) { + return "interface " + getParameterizedQualifiedSourceName(); + } + + return "class " + getParameterizedQualifiedSourceName(); } void addTypeParameter(JTypeParameter typeParameter) {
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JLowerBound.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JLowerBound.java new file mode 100644 index 0000000..111bfa9 --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JLowerBound.java
@@ -0,0 +1,60 @@ +/* + * Copyright 2007 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; + +/** + * Represents the super bound used in {@link JWildcardType}s. + */ +public class JLowerBound extends JBound { + /** + * + */ + public JLowerBound(JClassType lowerBound) { + this(new JClassType[] {lowerBound}); + } + + /** + * + */ + public JLowerBound(JClassType[] lowerBounds) { + super(lowerBounds); + } + + @Override + public JLowerBound isLowerBound() { + return this; + } + + @Override + public JUpperBound isUpperBound() { + return null; + } + + @Override + JClassType[] getSubtypes() { + return TypeOracle.NO_JCLASSES; + } + + @Override + boolean isAssignableFrom(JBound possibleSubWildcard) { + JLowerBound lowerBound = possibleSubWildcard.isLowerBound(); + if (lowerBound != null) { + return lowerBound.getFirstBound().isAssignableFrom(getFirstBound()); + } + + return false; + } +}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java index 6afd46f..bef2f11 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java
@@ -40,6 +40,12 @@ enclosingType.addMethod(this); } + JMethod(JClassType enclosingType, JMethod srcMethod) { + super(srcMethod); + this.enclosingType = enclosingType; + this.returnType = srcMethod.returnType; + } + @Override public JClassType getEnclosingType() { return enclosingType;
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameter.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameter.java index 07aaaf1..bf4b2b2 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameter.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameter.java
@@ -23,7 +23,7 @@ */ public class JParameter implements HasAnnotations, HasMetaData { - private final Annotations annotations = new Annotations(); + private final Annotations annotations; private final HasMetaData metaData = new MetaData(); @@ -45,9 +45,18 @@ enclosingMethod.addParameter(this); + annotations = new Annotations(); annotations.addAnnotations(declaredAnnotations); } + JParameter(JAbstractMethod enclosingMethod, JParameter srcParam) { + this.enclosingMethod = enclosingMethod; + this.type = srcParam.type; + this.name = srcParam.name; + this.annotations = new Annotations(srcParam.annotations); + MetaData.copy(this, srcParam); + } + public void addMetaData(String tagName, String[] values) { metaData.addMetaData(tagName, values); }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java index 46f375a..ad0a18f 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameterizedType.java
@@ -16,21 +16,92 @@ package com.google.gwt.core.ext.typeinfo; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** * Represents a parameterized type in a declaration. */ public class JParameterizedType extends JDelegatingClassType { + /** + * Create a parameterized type along with any necessary enclosing + * parameterized types. Enclosing parameterized types are necessary when the + * base type is a non-static member and the enclosing type is also generic. + */ + private static JParameterizedType createParameterizedTypeRecursive( + JGenericType baseType, Map<JClassType, JClassType> substitutionMap) { + JClassType enclosingType = null; + if (baseType.isMemberType() && !baseType.isStatic()) { + JGenericType isGenericEnclosingType = baseType.getEnclosingType().isGenericType(); + if (isGenericEnclosingType != null) { + enclosingType = createParameterizedTypeRecursive( + isGenericEnclosingType, substitutionMap); + } + } - private final Members members = new Members(this); + JTypeParameter[] typeParameters = baseType.getTypeParameters(); + JClassType[] newTypeArgs = new JClassType[typeParameters.length]; + TypeOracle oracle = baseType.getOracle(); + for (int i = 0; i < newTypeArgs.length; ++i) { + JClassType newTypeArg = substitutionMap.get(typeParameters[i]); + if (newTypeArg == null) { + JBound typeParamBounds = typeParameters[i].getBounds(); + JUpperBound newTypeArgBounds = new JUpperBound( + typeParamBounds.getFirstBound()); + newTypeArg = oracle.getWildcardType(newTypeArgBounds); + } + + newTypeArgs[i] = newTypeArg; + } + + // TODO: this is wrong if the generic type is a non-static inner class. + JParameterizedType parameterizedType = oracle.getParameterizedType( + baseType, enclosingType, newTypeArgs); + return parameterizedType; + } + + private final JClassType enclosingType; + + private List<JClassType> interfaces; + + private JClassType lazySuperclass; + + private final AbstractMembers members; private final List<JClassType> typeArgs = new ArrayList<JClassType>(); - JParameterizedType(JGenericType baseType) { + /** + * This map records the JClassType that should be used in place of a given + * {@link JTypeParameter}. + */ + private final Map<JTypeParameter, JClassType> substitutionMap = new IdentityHashMap<JTypeParameter, JClassType>(); + + public JParameterizedType(JGenericType baseType, JClassType enclosingType, + JClassType[] typeArgs) { super.setBaseType(baseType); - // TODO: type substitutions setting up fields/methods! + + this.enclosingType = enclosingType; + + // NOTE: this instance is not considered a nested type of the enclosing type + + final JParameterizedType parameterizedType = this; + members = new DelegateMembers(this, baseType, new Substitution() { + public JType getSubstitution(JType type) { + return type.getSubstitutedType(parameterizedType); + } + }); + + List<JClassType> typeArgsList = Arrays.asList(typeArgs); + this.typeArgs.addAll(typeArgsList); + assert (typeArgsList.indexOf(null) == -1); + + initializeTypeParameterSubstitutionMap(); + + // NOTE: Can't perform substitutions until we are done building } @Override @@ -53,8 +124,9 @@ return members.findNestedType(typeName); } + @Override public JGenericType getBaseType() { - return (JGenericType) baseType; + return (JGenericType) super.getBaseType(); } @Override @@ -69,6 +141,11 @@ } @Override + public JClassType getEnclosingType() { + return enclosingType; + } + + @Override public JField getField(String name) { return members.getField(name); } @@ -79,6 +156,19 @@ } @Override + public JClassType[] getImplementedInterfaces() { + if (interfaces == null) { + interfaces = new ArrayList<JClassType>(); + JClassType[] intfs = getBaseType().getImplementedInterfaces(); + for (JClassType intf : intfs) { + JClassType newIntf = intf.getSubstitutedType(this); + interfaces.add(newIntf); + } + } + return interfaces.toArray(TypeOracle.NO_JCLASSES); + } + + @Override public JMethod getMethod(String name, JType[] paramTypes) throws NotFoundException { return members.getMethod(name, paramTypes); @@ -120,19 +210,35 @@ @Override public String getParameterizedQualifiedSourceName() { StringBuffer sb = new StringBuffer(); - sb.append(getQualifiedSourceName()); - sb.append('<'); - boolean needComma = false; - for (JType typeArg : typeArgs) { - if (needComma) { - sb.append(", "); - } else { - needComma = true; - } - sb.append(typeArg.getParameterizedQualifiedSourceName()); + if (getEnclosingType() != null) { + sb.append(getEnclosingType().getParameterizedQualifiedSourceName()); + sb.append("."); + sb.append(getSimpleSourceName()); + } else { + sb.append(getQualifiedSourceName()); } - sb.append('>'); + + if (typeArgs.size() > 0) { + sb.append('<'); + boolean needComma = false; + for (JType typeArg : typeArgs) { + if (needComma) { + sb.append(", "); + } else { + needComma = true; + } + sb.append(typeArg.getParameterizedQualifiedSourceName()); + } + sb.append('>'); + } else { + /* + * Non-static, inner classes of generic types are modeled as generic, even + * if they do not declare type parameters or reference the type parameters + * of their enclosing generic type. + */ + } + return sb.toString(); } @@ -140,6 +246,7 @@ * Everything is fully qualified and includes the < and > in the * signature. */ + @Override public String getQualifiedSourceName() { return getBaseType().getQualifiedSourceName(); } @@ -151,8 +258,60 @@ /** * In this case, the raw type name. */ + @Override public String getSimpleSourceName() { - return getRawType().getSimpleSourceName(); + return getBaseType().getSimpleSourceName(); + } + + /* + * Goal: Return a list of possible subtypes of this parameterized type. In the + * event that we have generic subtypes and we cannot resolve the all of the + * type arguments, we need to wildcard types in place of the arguments that we + * cannot resolve. + * + * Algorithm: - Ask generic type for its subtypes - Filter subtypes of the + * generic which cannot be our subtype. + */ + @Override + public JClassType[] getSubtypes() { + List<JClassType> subtypeList = new ArrayList<JClassType>(); + + // Parameterized types are not tracked in the subtype hierarchy; ask base + // type + JClassType[] genericSubtypes = getBaseType().getSubtypes(); + for (JClassType subtype : genericSubtypes) { + Set<JClassType> typeHierarchy = getFlattenedTypeHierarchy(subtype); + + // Could be a subtype depending on how it is substituted + Map<JClassType, JClassType> substitutions = new IdentityHashMap<JClassType, JClassType>(); + if (isSubtype(subtype, typeHierarchy, substitutions, true)) { + JGenericType genericType = subtype.isGenericType(); + if (genericType != null) { + subtype = createParameterizedTypeRecursive(genericType, substitutions); + } + + subtypeList.add(subtype); + } + } + + return subtypeList.toArray(TypeOracle.NO_JCLASSES); + } + + @Override + public JClassType getSuperclass() { + if (isInterface() != null) { + return null; + } + + if (lazySuperclass == null) { + JGenericType baseType = getBaseType(); + JClassType superclass = baseType.getSuperclass(); + assert (superclass != null); + + lazySuperclass = superclass.getSubstitutedType(this); + } + + return lazySuperclass; } public JClassType[] getTypeArgs() { @@ -160,8 +319,24 @@ } @Override - public boolean isDefaultInstantiable() { - return getBaseType().isDefaultInstantiableIfParameterized(); + public boolean isAssignableFrom(JClassType possibleSubtype) { + if (possibleSubtype == this) { + return true; + } + + JRawType possibleRawSubtype = possibleSubtype.isRawType(); + if (possibleRawSubtype != null) { + return getBaseType().isAssignableFrom(possibleRawSubtype.getBaseType()); + } + + Set<JClassType> typeHierarchy = getFlattenedTypeHierarchy(possibleSubtype); + return isSubtype(possibleSubtype, typeHierarchy, + new IdentityHashMap<JClassType, JClassType>(), false); + } + + @Override + public boolean isAssignableTo(JClassType possibleSupertype) { + return possibleSupertype.isAssignableFrom(this); } @Override @@ -180,10 +355,31 @@ } @Override + public JWildcardType isWildcard() { + return null; + } + + /** + */ + public void setTypeArguments(JClassType[] typeArgs) { + this.typeArgs.addAll(Arrays.asList(typeArgs)); + } + + @Override + public String toString() { + if (isInterface() != null) { + return "interface " + getParameterizedQualifiedSourceName(); + } + + return "class " + getParameterizedQualifiedSourceName(); + } + + @Override protected JClassType findNestedTypeImpl(String[] typeName, int index) { return members.findNestedTypeImpl(typeName, index); } + @Override protected void getOverridableMethodsOnSuperclassesAndThisClass( Map<String, JMethod> methodsBySignature) { members.getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); @@ -197,14 +393,179 @@ * * @param methodsBySignature */ + @Override protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface( Map<String, JMethod> methodsBySignature) { members.getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); } - void addTypeArg(JClassType type) { - assert (type.isPrimitive() == null); - typeArgs.add(type); + @Override + JClassType getSubstitutedType(JParameterizedType parameterizedType) { + if (this == parameterizedType) { + return this; + } + + JClassType[] newTypeArgs = new JClassType[typeArgs.size()]; + for (int i = 0; i < newTypeArgs.length; ++i) { + newTypeArgs[i] = typeArgs.get(i).getSubstitutedType(parameterizedType); + } + + return getOracle().getParameterizedType(getBaseType(), getEnclosingType(), + newTypeArgs); } -} + /** + * Returns the {@link JClassType} that is a substitute for the given + * {@link JTypeParameter}. If there is no substitution, the original + * {@link JTypeParameter} is returned. + */ + JClassType getTypeParameterSubstitution(JTypeParameter typeParameter) { + JClassType substitute = substitutionMap.get(typeParameter); + if (substitute != null) { + return substitute; + } + + return typeParameter; + } + + boolean hasTypeArgs(JClassType[] otherArgTypes) { + if (otherArgTypes.length != typeArgs.size()) { + return false; + } + + for (int i = 0; i < otherArgTypes.length; ++i) { + // Identity tests are ok since identity is durable within an oracle. + // + if (otherArgTypes[i] != typeArgs.get(i)) { + return false; + } + } + + return true; + } + + /** + * Initialize a map of substitutions for {@link JTypeParameter}s to + * corresponding {@link JClassType}s. + */ + void initializeTypeParameterSubstitutionMap() { + JParameterizedType currentParameterizedType = this; + + while (currentParameterizedType != null) { + JGenericType genericType = currentParameterizedType.getBaseType(); + JTypeParameter[] typeParameters = genericType.getTypeParameters(); + JClassType[] typeArguments = currentParameterizedType.getTypeArgs(); + + for (JTypeParameter typeParameter : typeParameters) { + substitutionMap.put(typeParameter, + typeArguments[typeParameter.getOrdinal()]); + } + + if (currentParameterizedType.isStatic()) { + break; + } + + JClassType maybeParameterizedType = currentParameterizedType.getEnclosingType(); + if (maybeParameterizedType == null + || maybeParameterizedType.isParameterized() == null) { + break; + } + currentParameterizedType = maybeParameterizedType.isParameterized(); + } + } + + /** + * Returns the flattened view of the type hierarchy. + */ + private Set<JClassType> getFlattenedTypeHierarchy(JClassType type) { + Set<JClassType> typesSeen = new HashSet<JClassType>(); + getFlattenedTypeHierarchyRecursive(type, typesSeen); + return typesSeen; + } + + private void getFlattenedTypeHierarchyRecursive(JClassType type, + Set<JClassType> typesSeen) { + if (typesSeen.contains(type)) { + return; + } + typesSeen.add(type); + + // Superclass + JClassType superclass = type.getSuperclass(); + if (superclass != null) { + getFlattenedTypeHierarchyRecursive(superclass, typesSeen); + } + + // Check the interfaces + JClassType[] intfs = type.getImplementedInterfaces(); + for (JClassType intf : intfs) { + getFlattenedTypeHierarchyRecursive(intf, typesSeen); + } + } + + /** + * Look at the type hierarchy and see if we can find a parameterized type that + * has the same base type as this instance. If we find one then we check to + * see if the type arguments are compatible. If they are, then we record what + * the typeArgument needs to be replaced with in order to make it a proper + * subtype of this parameterized type. + */ + private boolean isSubtype(JClassType subtype, Set<JClassType> typeHierarchy, + Map<JClassType, JClassType> substitutions, boolean lookForSubstitutions) { + if (typeHierarchy.contains(this)) { + return true; + } + + for (JClassType type : typeHierarchy) { + JParameterizedType parameterizedType = type.isParameterized(); + if (parameterizedType == null) { + continue; + } + + if (parameterizedType.getBaseType() != getBaseType()) { + continue; + } + + // Check the type arguments to see if they are compatible. + JClassType[] otherTypeArgs = parameterizedType.getTypeArgs(); + JClassType[] myTypeArgs = getTypeArgs(); + boolean validSubstitution = true; + for (int i = 0; i < myTypeArgs.length; ++i) { + JClassType otherTypeArg = otherTypeArgs[i]; + JClassType myTypeArg = myTypeArgs[i]; + + validSubstitution = myTypeArg == otherTypeArg; + if (!validSubstitution) { + if (lookForSubstitutions) { + // Make sure that the other type argument is assignable from mine + validSubstitution = otherTypeArg.isAssignableFrom(myTypeArg); + } else { + // Looking for strict subtypes; only wildcards allow a non-exact + // match + JWildcardType isWildcard = myTypeArg.isWildcard(); + if (isWildcard != null) { + validSubstitution = myTypeArg.isAssignableFrom(otherTypeArg); + } + } + } + + if (!validSubstitution) { + break; + } + + substitutions.put(otherTypeArg, myTypeArg); + } + + if (validSubstitution) { + /* + * At this point we know that the type can be a subtype and we know the + * substitution to apply. + */ + return true; + } + } + + // Can't be a subtype regardless of substitution. + return false; + } +} \ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JPrimitiveType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JPrimitiveType.java index fbbb82c..2d1e9ce 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JPrimitiveType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JPrimitiveType.java
@@ -66,7 +66,7 @@ public JType getErasedType() { return this; } - + @Override public String getJNISignature() { return jni; @@ -95,6 +95,11 @@ } @Override + public JEnumType isEnum() { + return null; + } + + @Override public JClassType isInterface() { // intentional null return null; @@ -116,4 +121,14 @@ // intentional null return null; } + + @Override + public JWildcardType isWildcard() { + return null; + } + + @Override + JPrimitiveType getSubstitutedType(JParameterizedType parameterizedType) { + return this; + } }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java index a4aceca..2d207e2 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRawType.java
@@ -15,18 +15,46 @@ */ package com.google.gwt.core.ext.typeinfo; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; /** * Represents a raw type; that is a generic type with no type arguments. */ public class JRawType extends JDelegatingClassType { + private static final Substitution ERASURE_SUBSTITUTION = new Substitution() { + public JType getSubstitution(JType type) { + return type.getErasedType(); + } + }; - private final Members members = new Members(this); + private static JClassType normalizeType(JClassType type) { + JRawType isRawType = type.isRawType(); + if (isRawType != null) { + return isRawType.getGenericType(); + } - public JRawType(JGenericType genericType) { + JParameterizedType isParameterized = type.isParameterized(); + if (isParameterized != null) { + return isParameterized.getBaseType(); + } + + return type; + } + + private final JClassType enclosingType; + + private List<JClassType> interfaces; + + private final AbstractMembers members; + + public JRawType(JGenericType genericType, JClassType enclosingType) { super.setBaseType(genericType); - // TODO: type substitutions setting up fields/methods! + this.enclosingType = enclosingType; + + // NOTE: this instance is not considered a nested type of the enclosing type + + members = new DelegateMembers(this, getBaseType(), ERASURE_SUBSTITUTION); } @Override @@ -49,8 +77,11 @@ return members.findNestedType(typeName); } + @Override public JGenericType getBaseType() { - return (JGenericType) baseType; + JGenericType genericType = super.getBaseType().isGenericType(); + assert (genericType != null); + return genericType; } @Override @@ -79,6 +110,19 @@ } @Override + public JClassType[] getImplementedInterfaces() { + if (interfaces == null) { + interfaces = new ArrayList<JClassType>(); + JClassType[] intfs = getBaseType().getImplementedInterfaces(); + for (JClassType intf : intfs) { + JClassType newIntf = intf.getErasedType(); + interfaces.add(newIntf); + } + } + return interfaces.toArray(TypeOracle.NO_JCLASSES); + } + + @Override public JMethod getMethod(String name, JType[] paramTypes) throws NotFoundException { return members.getMethod(name, paramTypes); @@ -116,12 +160,12 @@ @Override public String getQualifiedSourceName() { - return baseType.getQualifiedSourceName(); + return getBaseType().getQualifiedSourceName(); } @Override public String getSimpleSourceName() { - return baseType.getSimpleSourceName(); + return getBaseType().getSimpleSourceName(); } @Override @@ -141,8 +185,25 @@ } @Override - public boolean isDefaultInstantiable() { - return getBaseType().isDefaultInstantiableIfParameterized(); + public JClassType getSuperclass() { + JClassType baseSuper = getBaseType().getSuperclass(); + if (baseSuper == null) { + return null; + } + + return baseSuper.getErasedType(); + } + + @Override + public boolean isAssignableFrom(JClassType possibleSubtype) { + JClassType type = normalizeType(possibleSubtype); + return getBaseType().isAssignableFrom(type); + } + + @Override + public boolean isAssignableTo(JClassType possibleSupertype) { + JClassType type = normalizeType(possibleSupertype); + return getBaseType().isAssignableTo(type); } @Override @@ -161,25 +222,15 @@ } @Override - protected JClassType findNestedTypeImpl(String[] typeName, int index) { - return members.findNestedTypeImpl(typeName, index); + public JWildcardType isWildcard() { + return null; } - protected void getOverridableMethodsOnSuperclassesAndThisClass( - Map<String, JMethod> methodsBySignature) { - members.getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); - } - - /** - * Gets the methods declared in interfaces that this type extends. If this - * type is a class, its own methods are not added. If this type is an - * interface, its own methods are added. Used internally by - * {@link #getOverridableMethods()}. - * - * @param methodsBySignature - */ - protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface( - Map<String, JMethod> methodsBySignature) { - members.getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); + @Override + JRawType getSubstitutedType(JParameterizedType parameterizedType) { + /* + * Raw types do not participate in substitution. + */ + return this; } }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java index c0c84d3..74da5ea 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
@@ -59,7 +59,7 @@ private String lazyQualifiedName; - private final Members members = new Members(this); + private final AbstractMembers members = new Members(this); private final HasMetaData metaData = new MetaData(); @@ -376,6 +376,11 @@ } @Override + public JEnumType isEnum() { + return null; + } + + @Override public JGenericType isGenericType() { return null; } @@ -439,13 +444,19 @@ return 0 != (modifierBits & TypeOracle.MOD_STATIC); } + @Override + public JWildcardType isWildcard() { + return null; + } + + @Override public void setSuperclass(JClassType type) { assert (type != null); assert (isInterface() == null); this.superclass = type; JRealClassType realSuperType; if (type.isParameterized() != null) { - realSuperType = type.isParameterized().getBaseType(); + realSuperType = (JRealClassType) type.isParameterized().getBaseType(); } else if (type.isRawType() != null) { realSuperType = type.isRawType().getGenericType(); } else { @@ -545,6 +556,11 @@ } } + @Override + JRealClassType getSubstitutedType(JParameterizedType parameterizedType) { + return this; + } + void notifySuperTypes() { notifySuperTypesOf(this); } @@ -555,5 +571,4 @@ void removeFromSupertypes() { removeSubtype(this); } - }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JType.java index 2ed4aad..c16d62c 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JType.java
@@ -59,6 +59,15 @@ return isInterface(); } + /** + * Returns this instance if it is an enumeration or <code>null</code> if it + * is not. + * + * @return this instance if it is an enumeration or <code>null</code> if it + * is not + */ + public abstract JEnumType isEnum(); + public abstract JClassType isInterface(); public abstract JParameterizedType isParameterized(); @@ -67,4 +76,19 @@ public abstract JRawType isRawType(); + public JTypeParameter isTypeParameter() { + return null; + } + + public abstract JWildcardType isWildcard(); + + /** + * Returns either the substitution of this type based on the parameterized + * type or this instance. + * + * @param parameterizedType + * @return either the substitution of this type based on the parameterized + * type or this instance + */ + abstract JType getSubstitutedType(JParameterizedType parameterizedType); }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java index cfea518..58cb21d 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JTypeParameter.java
@@ -15,6 +15,9 @@ */ package com.google.gwt.core.ext.typeinfo; +import java.util.ArrayList; +import java.util.List; + /** * Represents one of the type parameters in a generic type. */ @@ -22,30 +25,35 @@ private JBound bounds; private final JGenericType declaringClass; private final JAbstractMethod declaringMethod; + private final int ordinal; private final String typeName; - public JTypeParameter(String typeName, JAbstractMethod declaringMethod) { + public JTypeParameter(String typeName, JAbstractMethod declaringMethod, + int ordinal) { this.typeName = typeName; this.declaringMethod = declaringMethod; this.declaringClass = null; + this.ordinal = ordinal; declaringMethod.addTypeParameter(this); } - public JTypeParameter(String typeName, JGenericType declaringClass) { + public JTypeParameter(String typeName, JGenericType declaringClass, + int ordinal) { this.typeName = typeName; this.declaringClass = declaringClass; this.declaringMethod = null; + this.ordinal = ordinal; declaringClass.addTypeParameter(this); } @Override public JField findField(String name) { - return baseType.findField(name); + return getBaseType().findField(name); } @Override public JMethod findMethod(String name, JType[] paramTypes) { - return baseType.findMethod(name, paramTypes); + return getBaseType().findMethod(name, paramTypes); } public JBound getBounds() { @@ -58,47 +66,71 @@ @Override public JField getField(String name) { - return baseType.getField(name); + return getBaseType().getField(name); } @Override public JField[] getFields() { - return baseType.getFields(); + return getBaseType().getFields(); } public JClassType getFirstBound() { - return baseType; + return getBaseType(); } @Override public JMethod getMethod(String name, JType[] paramTypes) throws NotFoundException { - return baseType.getMethod(name, paramTypes); + return getBaseType().getMethod(name, paramTypes); } @Override public JMethod[] getMethods() { - return baseType.getMethods(); + return getBaseType().getMethods(); } @Override public String getName() { return typeName; } - + @Override public String getParameterizedQualifiedSourceName() { return typeName; } - + @Override public String getQualifiedSourceName() { - return typeName; + return typeName + bounds.getQualifiedSourceName(); } @Override public String getSimpleSourceName() { - return typeName; + return typeName + bounds.getSimpleSourceName(); + } + + @Override + public JClassType[] getSubtypes() { + JClassType[] subtypes = super.getSubtypes(); + List<JClassType> intersectionTypes = new ArrayList<JClassType>(); + for (JClassType subtype : subtypes) { + if (isAssignableFrom(subtype)) { + intersectionTypes.add(subtype); + } + } + return intersectionTypes.toArray(TypeOracle.NO_JCLASSES); + } + + @Override + public boolean isAssignableFrom(JClassType possibleSubtype) { + // TODO: Should this compute an intersection? + return getFirstBound().isAssignableFrom(possibleSubtype); + } + + @Override + public boolean isAssignableTo(JClassType possibleSupertype) { + // TODO: Should this compute an intersection? + return getFirstBound().isAssignableTo(possibleSupertype); } @Override @@ -116,6 +148,16 @@ return null; } + @Override + public JTypeParameter isTypeParameter() { + return this; + } + + @Override + public JWildcardType isWildcard() { + return null; + } + public void setBounds(JBound bounds) { this.bounds = bounds; super.setBaseType(bounds.getFirstBound()); @@ -123,10 +165,19 @@ @Override public String toString() { - if (baseType.isInterface() != null) { + if (getBaseType().isInterface() != null) { return "interface " + getQualifiedSourceName(); } else { return "class " + getQualifiedSourceName(); } } + + int getOrdinal() { + return ordinal; + } + + @Override + JClassType getSubstitutedType(JParameterizedType parameterizedType) { + return parameterizedType.getTypeParameterSubstitution(this); + } }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JUpperBound.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JUpperBound.java new file mode 100644 index 0000000..3762cd9 --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JUpperBound.java
@@ -0,0 +1,64 @@ +/* + * Copyright 2007 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; + +/** + * Represents the extends bound used in {@link JTypeParameter}s and + * {@link JWildcardType}s. + */ +public class JUpperBound extends JBound { + public JUpperBound(JClassType upperBound) { + this(new JClassType[] {upperBound}); + } + + /** + * + */ + public JUpperBound(JClassType[] upperBounds) { + super(upperBounds); + } + + @Override + public JLowerBound isLowerBound() { + return null; + } + + @Override + public JUpperBound isUpperBound() { + return this; + } + + @Override + JClassType[] getSubtypes() { + return getFirstBound().getSubtypes(); + } + + @Override + boolean isAssignableFrom(JBound possibleSubWildcard) { + JClassType firstBound = getFirstBound(); + + JUpperBound upperBound = possibleSubWildcard.isUpperBound(); + if (upperBound != null) { + // Upper bound + return firstBound.isAssignableFrom(upperBound.getFirstBound()); + } + + // Lower bound + JClassType javaLangObject = firstBound.getOracle().getJavaLangObject(); + return firstBound == javaLangObject + && possibleSubWildcard.getFirstBound() == javaLangObject; + } +}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java index 2cece8a..580e966 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JWildcardType.java
@@ -19,22 +19,21 @@ * Represents a wildcard type argument to a parameterized type. */ public class JWildcardType extends JDelegatingClassType implements HasBounds { - private final JBound bounds; public JWildcardType(JBound bounds) { - this.bounds = bounds; super.setBaseType(bounds.getFirstBound()); + this.bounds = bounds; } @Override public JField findField(String name) { - return baseType.findField(name); + return getBaseType().findField(name); } @Override public JMethod findMethod(String name, JType[] paramTypes) { - return baseType.findMethod(name, paramTypes); + return getBaseType().findMethod(name, paramTypes); } public JBound getBounds() { @@ -43,37 +42,52 @@ @Override public JField getField(String name) { - return baseType.getField(name); + return getBaseType().getField(name); } @Override public JField[] getFields() { - return baseType.getFields(); + return getBaseType().getFields(); } public JClassType getFirstBound() { - return baseType; + return getBounds().getFirstBound(); } @Override public JMethod getMethod(String name, JType[] paramTypes) throws NotFoundException { - return baseType.getMethod(name, paramTypes); + return getBaseType().getMethod(name, paramTypes); } @Override public JMethod[] getMethods() { - return baseType.getMethods(); + return getBaseType().getMethods(); } @Override public String getQualifiedSourceName() { - return "?"; + return "?" + bounds.getQualifiedSourceName(); } @Override public String getSimpleSourceName() { - return "?"; + return "?" + bounds.getSimpleSourceName(); + } + + @Override + public JClassType[] getSubtypes() { + return bounds.getSubtypes(); + } + + @Override + public boolean isAssignableFrom(JClassType possibleSubtype) { + JWildcardType possibleSubWildcard = possibleSubtype.isWildcard(); + if (possibleSubWildcard != null) { + return getBounds().isAssignableFrom(possibleSubWildcard.getBounds()); + } + + return getBaseType().isAssignableFrom(possibleSubtype); } @Override @@ -90,4 +104,51 @@ public JRawType isRawType() { return null; } + + @Override + public JWildcardType isWildcard() { + return this; + } + + @Override + JClassType getSubstitutedType(JParameterizedType parameterizedType) { + JClassType[] currentBounds = bounds.getBounds(); + JClassType[] newBounds = new JClassType[currentBounds.length]; + for (int i = 0; i < currentBounds.length; ++i) { + newBounds[i] = currentBounds[i].getSubstitutedType(parameterizedType); + } + + JBound newBound = bounds.isLowerBound() != null + ? new JLowerBound(newBounds) : new JUpperBound(newBounds); + return getOracle().getWildcardType(newBound); + } + + /** + * Returns <code>true</code> if this instance has the same bounds that are + * requested. + * + * @param otherBounds + * @return <code>true</code> if this instance has the same bounds that are + * requested + */ + boolean hasBounds(JBound otherBounds) { + if ((bounds.isUpperBound() != null && otherBounds.isLowerBound() != null) + || (bounds.isLowerBound() != null && otherBounds.isUpperBound() != null)) { + return false; + } + + JClassType[] boundTypes = bounds.getBounds(); + JClassType[] otherBoundTypes = otherBounds.getBounds(); + + if (boundTypes.length != otherBoundTypes.length) { + return false; + } + + for (int i = 0; i < boundTypes.length; ++i) { + if (boundTypes[i] != otherBoundTypes[i]) { + return false; + } + } + return true; + } }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/Members.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/Members.java index f77b78e..7ff2d8b 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/Members.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/Members.java
@@ -16,249 +16,34 @@ package com.google.gwt.core.ext.typeinfo; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; /** * A container for methods and fields. */ -class Members { - - protected final List<JConstructor> constructors = new ArrayList<JConstructor>(); - private JMethod[] cachedOverridableMethods; - private final JClassType classType; +class Members extends AbstractMembers { + private final List<JConstructor> constructors = new ArrayList<JConstructor>(); private final Map<String, JField> fields = new HashMap<String, JField>(); private final Map<String, List<JMethod>> methods = new HashMap<String, List<JMethod>>(); - private final Map<String, JClassType> nestedTypes = new HashMap<String, JClassType>(); public Members(JClassType classType) { - this.classType = classType; + super(classType); } - public JConstructor findConstructor(JType[] paramTypes) { - JConstructor[] ctors = getConstructors(); - for (int i = 0; i < ctors.length; i++) { - JConstructor candidate = ctors[i]; - if (candidate.hasParamTypes(paramTypes)) { - return candidate; - } - } - return null; + @Override + protected List<JConstructor> doGetConstructors() { + return constructors; } - public JField findField(String name) { - return fields.get(name); + @Override + protected Map<String, JField> doGetFields() { + return fields; } - public JMethod findMethod(String name, JType[] paramTypes) { - JMethod[] overloads = getOverloads(name); - for (int i = 0; i < overloads.length; i++) { - JMethod candidate = overloads[i]; - if (candidate.hasParamTypes(paramTypes)) { - return candidate; - } - } - return null; + @Override + protected Map<String, List<JMethod>> doGetMethods() { + return methods; } - - public JClassType findNestedType(String typeName) { - String[] parts = typeName.split("\\."); - return findNestedTypeImpl(parts, 0); - } - - public JConstructor getConstructor(JType[] paramTypes) - throws NotFoundException { - JConstructor result = findConstructor(paramTypes); - if (result == null) { - throw new NotFoundException(); - } - return result; - } - - public JConstructor[] getConstructors() { - return constructors.toArray(TypeOracle.NO_JCTORS); - } - - public JField getField(String name) { - JField field = findField(name); - assert (field != null); - return field; - } - - public JField[] getFields() { - return fields.values().toArray(TypeOracle.NO_JFIELDS); - } - - public JMethod getMethod(String name, JType[] paramTypes) - throws NotFoundException { - JMethod result = findMethod(name, paramTypes); - if (result == null) { - throw new NotFoundException(); - } - return result; - } - - public JMethod[] getMethods() { - List<JMethod> resultMethods = new ArrayList<JMethod>(); - for (List<JMethod> overloads : methods.values()) { - resultMethods.addAll(overloads); - } - return resultMethods.toArray(TypeOracle.NO_JMETHODS); - } - - public JClassType getNestedType(String typeName) throws NotFoundException { - JClassType result = findNestedType(typeName); - if (result == null) { - throw new NotFoundException(); - } - return result; - } - - public JClassType[] getNestedTypes() { - return nestedTypes.values().toArray(TypeOracle.NO_JCLASSES); - } - - public JMethod[] getOverloads(String name) { - List<?> resultMethods = methods.get(name); - if (resultMethods != null) { - return resultMethods.toArray(TypeOracle.NO_JMETHODS); - } else { - return TypeOracle.NO_JMETHODS; - } - } - - public JMethod[] getOverridableMethods() { - if (cachedOverridableMethods == null) { - Map<String, JMethod> methodsBySignature = new TreeMap<String, JMethod>(); - getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); - if (classType.isClass() != null) { - getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); - } - int size = methodsBySignature.size(); - Collection<JMethod> leafMethods = methodsBySignature.values(); - cachedOverridableMethods = leafMethods.toArray(new JMethod[size]); - } - return cachedOverridableMethods; - } - - protected void addConstructor(JConstructor ctor) { - assert (!constructors.contains(ctor)); - constructors.add(ctor); - } - - protected void addField(JField field) { - Object existing = fields.put(field.getName(), field); - assert (existing == null); - } - - protected void addMethod(JMethod method) { - String methodName = method.getName(); - List<JMethod> overloads = methods.get(methodName); - if (overloads == null) { - overloads = new ArrayList<JMethod>(); - methods.put(methodName, overloads); - } - overloads.add(method); - } - - protected void addNestedType(JClassType type) { - nestedTypes.put(type.getSimpleSourceName(), type); - } - - protected JClassType findNestedTypeImpl(String[] typeName, int index) { - JClassType found = nestedTypes.get(typeName[index]); - if (found == null) { - return null; - } else if (index < typeName.length - 1) { - return found.findNestedTypeImpl(typeName, index + 1); - } else { - return found; - } - } - - protected void getOverridableMethodsOnSuperclassesAndThisClass( - Map<String, JMethod> methodsBySignature) { - assert (classType.isClass() != null); - - // Recurse first so that more derived methods will clobber less derived - // methods. - JClassType superClass = classType.getSuperclass(); - if (superClass != null) { - superClass.getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); - } - - JMethod[] declaredMethods = getMethods(); - for (int i = 0; i < declaredMethods.length; i++) { - JMethod method = declaredMethods[i]; - - // Ensure that this method is overridable. - if (method.isFinal() || method.isPrivate()) { - // We cannot override this method, so skip it. - continue; - } - - // We can override this method, so record it. - String sig = computeInternalSignature(method); - methodsBySignature.put(sig, method); - } - } - - /** - * Gets the methods declared in interfaces that this type extends. If this - * type is a class, its own methods are not added. If this type is an - * interface, its own methods are added. Used internally by - * {@link #getOverridableMethods()}. - * - * @param methodsBySignature - */ - protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface( - Map<String, JMethod> methodsBySignature) { - // Recurse first so that more derived methods will clobber less derived - // methods. - JClassType[] superIntfs = classType.getImplementedInterfaces(); - for (int i = 0; i < superIntfs.length; i++) { - JClassType superIntf = superIntfs[i]; - superIntf.getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); - } - - if (classType.isInterface() == null) { - // This is not an interface, so we're done after having visited its - // implemented interfaces. - return; - } - - JMethod[] declaredMethods = getMethods(); - for (int i = 0; i < declaredMethods.length; i++) { - JMethod method = declaredMethods[i]; - - String sig = computeInternalSignature(method); - JMethod existing = methodsBySignature.get(sig); - if (existing != null) { - JClassType existingType = existing.getEnclosingType(); - JClassType thisType = method.getEnclosingType(); - if (thisType.isAssignableFrom(existingType)) { - // The existing method is in a more-derived type, so don't replace it. - continue; - } - } - methodsBySignature.put(sig, method); - } - } - - private String computeInternalSignature(JMethod method) { - StringBuffer sb = new StringBuffer(); - sb.setLength(0); - sb.append(method.getName()); - JParameter[] params = method.getParameters(); - for (int j = 0; j < params.length; j++) { - JParameter param = params[j]; - sb.append("/"); - sb.append(param.getType().getQualifiedSourceName()); - } - return sb.toString(); - } - } \ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/MetaData.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/MetaData.java index 92fb5ba..dd4adaf 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/MetaData.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/MetaData.java
@@ -24,6 +24,23 @@ class MetaData implements HasMetaData { + /** + * Copy metadata from one metadata container to another. Perhaps overly + * paranoid but HasMetaData elements are mutable. + * + * @param dest + * @param src + */ + static void copy(HasMetaData dest, HasMetaData src) { + String[] tagNames = src.getMetaDataTags(); + for (String tagName : tagNames) { + String[][] tagValueSets = src.getMetaData(tagName); + for (String[] tagValues : tagValueSets) { + dest.addMetaData(tagName, tagValues); + } + } + } + private final Map<String, List<String[]>> tagNameToStringArrayList = new HashMap<String, List<String[]>>(); public void addMetaData(String tagName, String[] values) { @@ -83,4 +100,5 @@ } return sb.toString(); } + }
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/Substitution.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/Substitution.java new file mode 100644 index 0000000..f9df504 --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/Substitution.java
@@ -0,0 +1,25 @@ +/* + * Copyright 2007 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; + +/** + * Interface used to perform type parameter substitutions or raw type + * substitutions. + */ +interface Substitution { + JType getSubstitution(JType type); +}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java index d657e71..dab0a9e 100644 --- a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java +++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
@@ -53,14 +53,12 @@ * </p> */ public class TypeOracle { - /** * A reserved metadata tag to indicates that a field type, method return type * or method parameter type is intended to be parameterized. Note that * constructor type parameters are not supported at present. */ public static final String TAG_TYPEARGS = "gwt.typeArgs"; - static final int MOD_ABSTRACT = 0x00000001; static final int MOD_FINAL = 0x00000002; static final int MOD_NATIVE = 0x00000004; @@ -69,8 +67,8 @@ static final int MOD_PUBLIC = 0x00000020; static final int MOD_STATIC = 0x00000040; static final int MOD_TRANSIENT = 0x00000080; - static final int MOD_VOLATILE = 0x00000100; + static final int MOD_VOLATILE = 0x00000100; static final Annotation[] NO_ANNOTATIONS = new Annotation[0]; static final JClassType[] NO_JCLASSES = new JClassType[0]; static final JConstructor[] NO_JCTORS = new JConstructor[0]; @@ -174,12 +172,14 @@ private final Map<String, JPackage> packages = new HashMap<String, JPackage>(); - private final Map<String, JParameterizedType> parameterizedTypes = new HashMap<String, JParameterizedType>(); + private final Map<String, List<JParameterizedType>> parameterizedTypes = new HashMap<String, List<JParameterizedType>>(); private int reloadCount = 0; private final Map<CompilationUnitProvider, JClassType[]> typesByCup = new IdentityHashMap<CompilationUnitProvider, JClassType[]>(); + private final Map<String, List<JWildcardType>> wildcardTypes = new HashMap<String, List<JWildcardType>>(); + public TypeOracle() { // Always create the default package. // @@ -320,25 +320,65 @@ * the same arguments return the same object. * * @param genericType a generic base class + * @param enclosingType + * @param typeArgs the type arguments bound to the specified generic type + * @return a type object representing this particular binding of type + * arguments to the specified generic + */ + public JParameterizedType getParameterizedType(JGenericType genericType, + JClassType enclosingType, JClassType[] typeArgs) { + + if (genericType.isMemberType()) { + if (genericType.getEnclosingType().isGenericType() != null + && enclosingType.isParameterized() == null + && enclosingType.isRawType() == null) { + throw new IllegalArgumentException( + "enclosingType needs to be a parameterized type or a raw type"); + } + } + + // TODO: validate that the type arguments satisfy the generic type parameter + // bounds if any were specified + + // Uses the generated string signature to intern parameterized types. + // + JParameterizedType parameterized = new JParameterizedType(genericType, + enclosingType, typeArgs); + + // TODO: parameterized qualified source name does not account for the type + // args of the enclosing type + String sig = parameterized.getParameterizedQualifiedSourceName(); + List<JParameterizedType> candidates = parameterizedTypes.get(sig); + if (candidates == null) { + candidates = new ArrayList<JParameterizedType>(); + parameterizedTypes.put(sig, candidates); + } else { + for (JParameterizedType candidate : candidates) { + if (candidate.hasTypeArgs(typeArgs)) { + return candidate; + } + } + } + + candidates.add(parameterized); + + return parameterized; + } + + /** + * Gets the parameterized type object that represents the combination of a + * specified raw type and a set of type arguments. The returned type always + * has a stable identity so as to guarantee that all calls to this method with + * the same arguments return the same object. + * + * @param genericType a generic base class * @param typeArgs the type arguments bound to the specified generic type * @return a type object representing this particular binding of type * arguments to the specified generic */ public JParameterizedType getParameterizedType(JGenericType genericType, JClassType[] typeArgs) { - // Uses the generated string signature to intern parameterized types. - // - JParameterizedType parameterized = new JParameterizedType(genericType); - for (int i = 0; i < typeArgs.length; i++) { - parameterized.addTypeArg(typeArgs[i]); - } - String sig = parameterized.getParameterizedQualifiedSourceName(); - JParameterizedType existing = parameterizedTypes.get(sig); - if (existing == null) { - parameterizedTypes.put(sig, parameterized); - existing = parameterized; - } - return existing; + return getParameterizedType(genericType, null, typeArgs); } public long getReloadCount() { @@ -404,6 +444,26 @@ } } + public JWildcardType getWildcardType(JBound bounds) { + JWildcardType wildcardType = new JWildcardType(bounds); + String sig = wildcardType.getQualifiedSourceName(); + List<JWildcardType> candidates = wildcardTypes.get(sig); + if (candidates == null) { + candidates = new ArrayList<JWildcardType>(); + wildcardTypes.put(sig, candidates); + } else { + for (JWildcardType candidate : candidates) { + if (candidate.hasBounds(bounds)) { + return candidate; + } + } + } + + candidates.add(wildcardType); + + return wildcardType; + } + /** * Parses the string form of a type to produce the corresponding type object. * The types that can be parsed include primitives, class and interface names, @@ -500,7 +560,7 @@ /** * Note, this method is called reflectively from the - * {@link CacheManager#invalidateOnRefresh(TypeOracle)} + * {@link CacheManager#invalidateOnRefresh(TypeOracle)}. * * @param cup compilation unit whose types will be invalidated */ @@ -878,18 +938,21 @@ /** * Remove any parameterized type that was invalidated because either its raw - * type or any one of its type arguements was invalidated. + * type or any one of its type arguments was invalidated. * * @param invalidTypes set of types known to have been invalidated */ private void removeInvalidatedParameterizedTypes(Set<JClassType> invalidTypes) { - Iterator<JParameterizedType> iter = parameterizedTypes.values().iterator(); + Iterator<List<JParameterizedType>> listIterator = parameterizedTypes.values().iterator(); - while (iter.hasNext()) { - JType type = iter.next(); - - if (isInvalidatedTypeRecursive(type, invalidTypes)) { - iter.remove(); + while (listIterator.hasNext()) { + List<JParameterizedType> list = listIterator.next(); + Iterator<JParameterizedType> typeIterator = list.iterator(); + while (typeIterator.hasNext()) { + JType type = typeIterator.next(); + if (isInvalidatedTypeRecursive(type, invalidTypes)) { + typeIterator.remove(); + } } } }
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java b/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java index 79b2f4e..c93536a 100644 --- a/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java +++ b/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java
@@ -186,6 +186,7 @@ // See if the value was explicitly declared Object value = identifierToValue.get(name); if (value != null) { + assert (method.getReturnType().isAssignableFrom(value.getClass())); return value; } @@ -197,6 +198,11 @@ return annotationMethod.getDefaultValue(); } + if (method.getDeclaringClass() == Annotation.class + && "annotationType".equals(method.getName())) { + return annotationClass; + } + /* * Maybe it's an Object method, just delegate to myself. */
diff --git a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java index 904f5d5..4e84999 100644 --- a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java +++ b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
@@ -26,8 +26,11 @@ import com.google.gwt.core.ext.typeinfo.JBound; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JConstructor; +import com.google.gwt.core.ext.typeinfo.JEnumConstant; +import com.google.gwt.core.ext.typeinfo.JEnumType; import com.google.gwt.core.ext.typeinfo.JField; import com.google.gwt.core.ext.typeinfo.JGenericType; +import com.google.gwt.core.ext.typeinfo.JLowerBound; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JPackage; import com.google.gwt.core.ext.typeinfo.JParameter; @@ -36,8 +39,9 @@ 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.JUpperBound; import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.dev.jdt.CacheManager.Mapper; import com.google.gwt.dev.util.Empty; import com.google.gwt.dev.util.Util; @@ -46,6 +50,7 @@ import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; @@ -68,9 +73,8 @@ import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.NumberLiteral; -import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; -import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.TrueLiteral; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; @@ -101,6 +105,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.Array; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -112,7 +117,7 @@ import java.util.regex.Pattern; /** - * Builds a {@link com.google.gwt.dev.typeinfo.TypeOracle} from a set of + * Builds a {@link com.google.gwt.core.ext.typeinfo.TypeOracle} from a set of * compilation units. * <p> * For example, @@ -128,7 +133,7 @@ * </pre> */ public class TypeOracleBuilder { - + private static final JClassType[] NO_JCLASSES = new JClassType[0]; private static final Pattern PATTERN_WHITESPACE = Pattern.compile("\\s"); public static String computeBinaryClassName(JType type) { @@ -283,6 +288,22 @@ return "package-info".equals(qname); } + private static boolean maybeGeneric(TypeDeclaration typeDecl) { + if (typeDecl.typeParameters != null) { + // Definitely generic since it has type parameters + return true; + } + + if (!typeDecl.binding.isStatic() && typeDecl.enclosingType != null) { + // Consider typeDecl to be generic if it is not static and its enclosing + // type is generic + return maybeGeneric(typeDecl.enclosingType); + } + + return false; + } + + // TODO: move into the Annotations class or create an AnnotationsUtil class? private static HashMap<Class<? extends java.lang.annotation.Annotation>, java.lang.annotation.Annotation> newAnnotationMap() { return new HashMap<Class<? extends java.lang.annotation.Annotation>, java.lang.annotation.Annotation>(); } @@ -498,46 +519,6 @@ cud.traverse(new ASTVisitor() { @Override - public boolean visit( - ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, - BlockScope scope) { - ParameterizedTypeBinding jparameterizedType = (ParameterizedTypeBinding) parameterizedQualifiedTypeReference.resolvedType; - processParameterizedType(jparameterizedType); - return true; // do nothing by default, keep traversing - } - - @Override - public boolean visit( - ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, - ClassScope scope) { - ParameterizedTypeBinding jparameterizedType = (ParameterizedTypeBinding) parameterizedQualifiedTypeReference.resolvedType; - processParameterizedType(jparameterizedType); - return true; // do nothing by default, keep traversing - } - - @Override - public boolean visit( - ParameterizedSingleTypeReference parameterizedSingleTypeReference, - BlockScope scope) { - if (parameterizedSingleTypeReference.resolvedType instanceof ParameterizedTypeBinding) { - ParameterizedTypeBinding jparameterizedType = (ParameterizedTypeBinding) parameterizedSingleTypeReference.resolvedType; - processParameterizedType(jparameterizedType); - } else if (parameterizedSingleTypeReference.resolvedType instanceof SourceTypeBinding) { - // nothing to do - } else { - assert false; - } - return true; // do nothing by default, keep traversing - } - - @Override - public boolean visit( - ParameterizedSingleTypeReference parameterizedSingleTypeReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - - @Override public boolean visit(TypeDeclaration typeDecl, BlockScope scope) { JClassType enclosingType = identityMapper.get(typeDecl.binding.enclosingType()); processType(typeDecl, enclosingType, true); @@ -609,20 +590,37 @@ return oracle; } - private JBound createTypeVariableBounds(TreeLogger logger, + private JUpperBound createTypeVariableBounds(TreeLogger logger, TypeVariableBinding tvBinding) { - TypeBinding firstBound = tvBinding.firstBound; - if (firstBound == null) { - firstBound = tvBinding.superclass; + TypeBinding jfirstBound = tvBinding.firstBound; + if (jfirstBound == null) { + // No bounds were specified, so we default to Object + JClassType upperBound = (JClassType) resolveType(logger, + tvBinding.superclass); + /* + * Can't test for equality with TypeOracle.getJavaLangObject() since it + * may not be initialized at this point + */ + assert (Object.class.getName().equals(upperBound.getQualifiedSourceName())); + return new JUpperBound(upperBound); } - JClassType firstBoundType = (JClassType) resolveType(logger, firstBound); - JBound bounds = new JBound(firstBoundType); - for (ReferenceBinding ref : tvBinding.superInterfaces()) { - JClassType bound = (JClassType) resolveType(logger, ref); - assert (bound.isInterface() != null); - bounds.addUpperBound(bound); + + List<JClassType> bounds = new ArrayList<JClassType>(); + JClassType firstBound = (JClassType) resolveType(logger, jfirstBound); + if (firstBound.isClass() != null) { + bounds.add(firstBound); } - return bounds; + + ReferenceBinding[] jsuperInterfaces = tvBinding.superInterfaces(); + for (ReferenceBinding jsuperInterface : jsuperInterfaces) { + JClassType superInterface = (JClassType) resolveType(logger, + jsuperInterface); + assert (superInterface != null); + assert (superInterface.isInterface() != null); + bounds.add(superInterface); + } + + return new JUpperBound(bounds.toArray(NO_JCLASSES)); } private Object evaluateAnnotationExpression(TreeLogger logger, @@ -650,6 +648,26 @@ return null; } + try { + Method method = clazz.getMethod(identifier, new Class[0]); + Class<?> expectedClass = method.getReturnType(); + Class<? extends Object> actualClass = value.getClass(); + if (expectedClass.isArray() && !actualClass.isArray()) { + /* + * JSL3 Section 9.7 single element annotations can skip the curly + * braces; means we do not get an array + */ + assert (expression instanceof SingleMemberAnnotation); + Object array = Array.newInstance(expectedClass.getComponentType(), 1); + Array.set(array, 0, value); + value = array; + } + } catch (SecurityException e) { + return null; + } catch (NoSuchMethodException e) { + return null; + } + identifierToValue.put(identifier, value); } @@ -796,6 +814,11 @@ } private String getQualifiedName(ReferenceBinding binding) { + if (binding.isMemberType()) { + return String.valueOf(CharOperation.concat( + binding.enclosingType().readableName(), binding.sourceName, '.')); + } + return CharOperation.toString(binding.compoundName); } @@ -812,15 +835,6 @@ } /** - * Maps a ParameterizedTypeBinding into a JParameterizedType. - */ - private void processParameterizedType(ParameterizedTypeBinding binding) { - TypeOracle oracle = cacheManager.getTypeOracle(); - // TODO Get the JParameterized type for the current binding, fill it out - // as you would a JClassType. - } - - /** * Maps a TypeDeclaration into a JClassType. */ private void processType(TypeDeclaration typeDecl, JClassType enclosingType, @@ -838,7 +852,7 @@ */ return; } - + String qname; String jclassName; if (binding instanceof LocalTypeBinding) { @@ -854,10 +868,10 @@ qname = getQualifiedName(binding); jclassName = getSimpleName(typeDecl); } + if (oracle.findType(qname) != null) { - // The oracle already knew about this type. - // Don't re-add it. - // + // TODO: gname of generic types includes the type arguments, I think that + // this would cause inner classes to not be found. return; } @@ -876,22 +890,17 @@ if (jclassIsAnnonation) { type = new JAnnotationType(oracle, cup, pkg, enclosingType, isLocalType, jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf); - } else if (typeDecl.typeParameters != null - && typeDecl.typeParameters.length > 0) { + } else if (maybeGeneric(typeDecl)) { type = new JGenericType(oracle, cup, pkg, enclosingType, isLocalType, jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf); - for (TypeParameter jtypeParameter : typeDecl.typeParameters) { - JTypeParameter typeParameter = new JTypeParameter( - String.valueOf(jtypeParameter.name), (JGenericType) type); - cacheManager.setTypeForBinding(jtypeParameter.binding, typeParameter); - } + } else if (binding.isEnum()) { + type = new JEnumType(oracle, cup, pkg, enclosingType, isLocalType, + jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf); } else { type = new JRealClassType(oracle, cup, pkg, enclosingType, isLocalType, jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf); } - // TODO: enums? - cacheManager.setTypeForBinding(binding, type); } @@ -945,7 +954,14 @@ } String name = String.valueOf(jfield.name); - JField field = new JField(enclosingType, name, declaredAnnotations); + JField field; + if (jfield.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { + assert (enclosingType.isEnum() != null); + field = new JEnumConstant(enclosingType, name, declaredAnnotations, + jfield.binding.original().id); + } else { + field = new JField(enclosingType, name, declaredAnnotations); + } // Get modifiers. // @@ -1014,6 +1030,12 @@ if (jmethod.isConstructor()) { method = new JConstructor(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd, declaredAnnotations); + + // Resolve the type parameters, since they may be used as the return type, + // etc. + if (!resolveTypeParameters(logger, method, jmethod.typeParameters())) { + return false; + } } else { if (jmethod.isAnnotationMethod()) { AnnotationMethodDeclaration annotationMethod = (AnnotationMethodDeclaration) jmethod; @@ -1029,25 +1051,12 @@ bodyStart, bodyEnd, declaredAnnotations); } - // Add declared type parameters. - if (jmethod.typeParameters() != null) { - for (TypeParameter jtypeParameter : jmethod.typeParameters()) { - JTypeParameter typeParameter = new JTypeParameter( - String.valueOf(jtypeParameter.name), method); - cacheManager.getIdentityMapper().put(jtypeParameter.binding, - typeParameter); - } - JTypeParameter[] typeParameters = method.getTypeParameters(); - for (TypeParameter jtypeParameter : jmethod.typeParameters()) { - JTypeParameter typeParameter = (JTypeParameter) cacheManager.getIdentityMapper().get( - jtypeParameter.binding); - JBound bounds = createTypeVariableBounds(logger, - jtypeParameter.binding); - typeParameter.setBounds(bounds); - } + // Resolve the type parameters, since they may be used as the return type, + // etc. + if (!resolveTypeParameters(logger, method, jmethod.typeParameters())) { + return false; } - // Add the return type if necessary. TypeBinding jreturnType = ((MethodDeclaration) jmethod).returnType.resolvedType; JType returnType = resolveType(logger, jreturnType); if (returnType == null) { @@ -1241,12 +1250,13 @@ // First check the type oracle to prefer type identity with the type // oracle we're assimilating into. // - String typeName = String.valueOf(referenceBinding.readableName()); + String typeName = getQualifiedName(referenceBinding); JType resolvedType = oracle.findType(typeName); if (resolvedType == null) { // Otherwise, it should be something we've mapped during this build. resolvedType = cacheManager.getTypeForBinding(referenceBinding); } + if (resolvedType != null) { if (binding instanceof RawTypeBinding) { // Use the raw type instead of the generic type. @@ -1284,78 +1294,104 @@ // Check for parameterized. if (binding instanceof ParameterizedTypeBinding) { ParameterizedTypeBinding ptBinding = (ParameterizedTypeBinding) binding; - JClassType[] typeArguments = new JClassType[ptBinding.arguments.length]; + + /* + * NOTE: it is possible for ParameterizedTypeBinding.arguments to be null. + * This can happen if a generic class has a non-static, non-generic, inner + * class that references a TypeParameter from its enclosing generic type. + * You would think that typeVariables() would do the right thing but it + * does not. + */ + TypeBinding[] arguments = ptBinding.arguments; + int nArguments = arguments != null ? arguments.length : 0; + JClassType[] typeArguments = new JClassType[nArguments]; + boolean failed = false; for (int i = 0; i < typeArguments.length; ++i) { - typeArguments[i] = (JClassType) resolveType(logger, - ptBinding.arguments[i]); + typeArguments[i] = (JClassType) resolveType(logger, arguments[i]); + if (typeArguments[i] == null) { + failed = true; + } } - JGenericType baseType = (JGenericType) resolveType(logger, ptBinding.type); - return oracle.getParameterizedType(baseType, typeArguments); + JClassType enclosingType = null; + if (ptBinding.enclosingType() != null) { + enclosingType = (JClassType) resolveType(logger, + ptBinding.enclosingType()); + if (enclosingType == null) { + failed = true; + } + } + + /* + * NOTE: In the case where a generic type has a nested, non-static, + * non-generic type. The type for the binding will not be a generic type. + */ + JType resolveType = resolveType(logger, ptBinding.type); + if (resolveType == null) { + failed = true; + } + + if (!failed) { + JEnumType enumType = resolveType.isEnum(); + if (enumType != null) { + /* + * An enumerated type that is nested within a generic type is referenced + * via a parameterized type by JDT. In this case we just return the + * enumerated type and don't treat it as a parameterized type since + * enumerations cannot be parameterized and are implicitly static. + */ + return enumType; + } + + JGenericType genericType = (JGenericType) resolveType; + return oracle.getParameterizedType(genericType, enclosingType, + typeArguments); + } else { + // Fall-through to failure + } } if (binding instanceof TypeVariableBinding) { TypeVariableBinding tvBinding = (TypeVariableBinding) binding; JTypeParameter typeParameter = (JTypeParameter) cacheManager.getTypeForBinding(tvBinding); assert (typeParameter != null); - - if (typeParameter.getBounds() == null) { - // Setup a dummy bound to prevent recursion - typeParameter.setBounds(new JBound(null)); - JBound bounds = createTypeVariableBounds(logger, tvBinding); - typeParameter.setBounds(bounds); - } return typeParameter; } if (binding instanceof WildcardBinding) { WildcardBinding wcBinding = (WildcardBinding) binding; + + assert (wcBinding.otherBounds == null); + JBound bounds; switch (wcBinding.boundKind) { case Wildcard.EXTENDS: { - JClassType firstBoundType = (JClassType) resolveType(logger, + assert (wcBinding.bound != null); + JClassType upperBound = (JClassType) resolveType(logger, wcBinding.bound); - bounds = new JBound(firstBoundType); - if (wcBinding.otherBounds != null) { - for (TypeBinding bound : wcBinding.otherBounds) { - JClassType boundType = (JClassType) resolveType(logger, bound); - bounds.addUpperBound(boundType); - } - } + bounds = new JUpperBound(new JClassType[] {upperBound}); } break; case Wildcard.SUPER: { - // TODO: verify - JClassType firstBoundType = (JClassType) resolveType(logger, - wcBinding.erasure()); - assert (firstBoundType.getQualifiedSourceName().equals("java.lang.Object")); - bounds = new JBound(firstBoundType); - assert (wcBinding.bound != null); - JClassType boundType = (JClassType) resolveType(logger, + JClassType lowerBound = (JClassType) resolveType(logger, wcBinding.bound); - bounds.addLowerBound(boundType); - if (wcBinding.otherBounds != null) { - for (TypeBinding bound : wcBinding.otherBounds) { - boundType = (JClassType) resolveType(logger, bound); - bounds.addLowerBound(boundType); - } - } + bounds = new JLowerBound(new JClassType[] {lowerBound}); } break; case Wildcard.UNBOUND: { - JClassType firstBoundType = (JClassType) resolveType(logger, + JClassType upperBound = (JClassType) resolveType(logger, wcBinding.erasure()); - assert (firstBoundType.getQualifiedSourceName().equals("java.lang.Object")); - bounds = new JBound(firstBoundType); + bounds = new JUpperBound(new JClassType[] {upperBound}); + assert (bounds.getFirstBound().getQualifiedSourceName().equals("java.lang.Object")); } break; default: assert false : "WildcardBinding of unknown boundKind???"; return null; } - JWildcardType wcType = new JWildcardType(bounds); - return wcType; + + return oracle.getWildcardType(bounds); } // Log other cases we know about that don't make sense. @@ -1411,9 +1447,11 @@ } type.addAnnotations(declaredAnnotations); - // Resolve type parameters - List<JTypeParameter> typeParameters = new ArrayList<JTypeParameter>(); - if (!resolveTypeParameters(logger, jclass.typeParameters, typeParameters)) { + // Resolve type parameters for generic types + JGenericType genericType = type.isGenericType(); + if (genericType != null + && !resolveTypeParameters(logger, type.isGenericType(), + jclass.typeParameters)) { // Failed to resolve return false; } @@ -1471,18 +1509,49 @@ } private boolean resolveTypeParameter(TreeLogger logger, - TypeParameter jtypeParameter, List<JTypeParameter> typeParameters) { - JTypeParameter typeParameter = (JTypeParameter) cacheManager.getIdentityMapper().get( - jtypeParameter.binding); - typeParameters.add(typeParameter); + JAbstractMethod method, TypeParameter jtypeParameter, int ordinal) { + JTypeParameter typeParameter = new JTypeParameter( + String.valueOf(jtypeParameter.name), method, ordinal); + return resolveTypeParameter(logger, jtypeParameter.binding, typeParameter); + } + + private boolean resolveTypeParameter(TreeLogger logger, + JGenericType genericType, TypeParameter jtypeParameter, int ordinal) { + JTypeParameter typeParameter = new JTypeParameter( + String.valueOf(jtypeParameter.name), genericType, ordinal); + return resolveTypeParameter(logger, jtypeParameter.binding, typeParameter); + } + + private boolean resolveTypeParameter(TreeLogger logger, + TypeVariableBinding binding, JTypeParameter typeParameter) { + Mapper identityMapper = cacheManager.getIdentityMapper(); + assert (identityMapper.get(binding) == null); + + identityMapper.put(binding, typeParameter); + + JBound bounds = createTypeVariableBounds(logger, binding); + typeParameter.setBounds(bounds); + return true; } private boolean resolveTypeParameters(TreeLogger logger, - TypeParameter[] jtypeParameters, List<JTypeParameter> typeParameters) { + JAbstractMethod method, TypeParameter[] jtypeParameters) { if (jtypeParameters != null) { for (int i = 0; i < jtypeParameters.length; ++i) { - if (!resolveTypeParameter(logger, jtypeParameters[i], typeParameters)) { + if (!resolveTypeParameter(logger, method, jtypeParameters[i], i)) { + return false; + } + } + } + return true; + } + + private boolean resolveTypeParameters(TreeLogger logger, + JGenericType genericType, TypeParameter[] jtypeParameters) { + if (jtypeParameters != null) { + for (int i = 0; i < jtypeParameters.length; ++i) { + if (!resolveTypeParameter(logger, genericType, jtypeParameters[i], i)) { return false; } }
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JArrayTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JArrayTypeTest.java new file mode 100644 index 0000000..8f7c829 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JArrayTypeTest.java
@@ -0,0 +1,194 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.test.CA; +import com.google.gwt.core.ext.typeinfo.test.CB; +import com.google.gwt.core.ext.typeinfo.test.MyCustomList; +import com.google.gwt.core.ext.typeinfo.test.MyList; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; + +import junit.framework.TestCase; + +/** + * Tests for {@link JArrayType}. + */ +public class JArrayTypeTest extends TestCase { + /* + * Returns int[][] + */ + private static JArrayType getIntArray(TypeOracle oracle) { + return oracle.getArrayType(getIntVector(oracle)); + } + /* + * Returns int[]. + */ + private static JArrayType getIntVector(TypeOracle oracle) { + return oracle.getArrayType(JPrimitiveType.INT); + } + + /* + * Returns Object[][] + */ + private static JArrayType getObjectArray(TypeOracle oracle) { + return oracle.getArrayType(getObjectVector(oracle)); + } + + /* + * Returns Object[]. + */ + private static JArrayType getObjectVector(TypeOracle oracle) { + return oracle.getArrayType(oracle.getJavaLangObject()); + } + + private final boolean logToConsole = false; + + private final ModuleContext moduleContext = new ModuleContext(logToConsole + ? new PrintWriterTreeLogger() : TreeLogger.NULL, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); + + public JArrayTypeTest() throws UnableToCompleteException { + } + + public void testGetSubtypes() throws NotFoundException { + JArrayType testArrayType = getTestArrayType(); + + JArrayType[] arraySubtypes = testArrayType.getSubtypes(); + assertEquals(2, arraySubtypes.length); + + for (int i = 0; i < arraySubtypes.length; ++i) { + assertTrue(testArrayType.isAssignableFrom(arraySubtypes[i])); + } + } + + public void testGetSuperclass() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JArrayType intVector = getIntVector(oracle); + JArrayType intArray = getIntArray(oracle); + JArrayType objVector = getObjectVector(oracle); + JArrayType objArray = getObjectArray(oracle); + + // Check that superclass of int[][] is Object[] + assertEquals(objVector, intArray.getSuperclass()); + + // Check that superclass of int[] is Object + assertEquals(oracle.getJavaLangObject(), intVector.getSuperclass()); + + // CA + JClassType caType = oracle.getType(CA.class.getCanonicalName()); + + // CA[] + JArrayType caVector = oracle.getArrayType(caType); + + // CA[][] + JArrayType caArray = oracle.getArrayType(caVector); + + // CB + JClassType cbType = oracle.getType(CB.class.getCanonicalName()); + + // CB[] + JArrayType cbVector = oracle.getArrayType(cbType); + + // CB[][] + JArrayType cbArray = oracle.getArrayType(cbVector); + + // Check that CB[][] has a supertype of CA[][] + JClassType cbArraySuper = cbArray.getSuperclass(); + assertEquals(caArray, cbArraySuper); + + // Check that CA[][] has a supertype of Object[][] + JClassType cbArraySuperSuper = cbArraySuper.getSuperclass(); + assertEquals(objArray, cbArraySuperSuper); + + // Check that Object[][] has supertype of Object[] + JClassType cbArraySuperSuperSuper = cbArraySuperSuper.getSuperclass(); + assertEquals(objVector, cbArraySuperSuperSuper); + + // Check that Object[] has supertype of Object + JClassType cbArraySuperSuperSuperSuper = cbArraySuperSuperSuper.getSuperclass(); + assertEquals(oracle.getJavaLangObject(), cbArraySuperSuperSuperSuper); + } + + public void testIsAssignableFrom() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + + JArrayType intVector = getIntVector(oracle); + JArrayType intArray = getIntArray(oracle); + JArrayType objVector = getObjectVector(oracle); + JArrayType objArray = getObjectArray(oracle); + + // Object[] is not assignable from int[] + assertFalse(objVector.isAssignableFrom(intVector)); + assertFalse(intVector.isAssignableFrom(objVector)); + + // Object[] is assignable from int[][] + assertTrue(objVector.isAssignableFrom(intArray)); + + // Object[] is assignable from Object[][] + assertTrue(objVector.isAssignableFrom(objArray)); + + // int[] is assignable from int[] + assertTrue(intVector.isAssignableFrom(intVector)); + + // int[] is assignable from int[][] + assertFalse(intArray.isAssignableFrom(intVector)); + + JClassType testSubtype = oracle.getType(MyCustomList.class.getName()); + + // MyCustomList[] + JArrayType testArraySubtype = oracle.getArrayType(testSubtype); + + // MyList[] is assignable from MyCustomList[] + assertTrue(getTestArrayType().isAssignableFrom(testArraySubtype)); + + // MyCustomList[] + JArrayType testVectorSubtype = oracle.getArrayType(testArraySubtype); + + // MyList[] is not assignable from MyCustomList[][] + assertFalse(getTestArrayType().isAssignableFrom(testVectorSubtype)); + + // MyCustomList[] is not assignable from MyList[] + assertFalse(testArraySubtype.isAssignableFrom(getTestArrayType())); + } + + public void testIsAssignableTo() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType testSubtype = oracle.getType(MyCustomList.class.getName()); + JArrayType testArraySubtype = oracle.getArrayType(testSubtype); + + // MyCustomList[] is assignable to MyList[] + assertTrue(testArraySubtype.isAssignableTo(getTestArrayType())); + + // MyCustomList[] is assignable to Object + assertTrue(testArraySubtype.isAssignableTo(oracle.getJavaLangObject())); + + // MyList[] is not assignable to MyCustomList[] + assertFalse(getTestArrayType().isAssignableTo(testArraySubtype)); + + // MyList[] is assignable to MyCustomList[] + assertFalse(getTestArrayType().isAssignableTo(testArraySubtype)); + + } + + private JArrayType getTestArrayType() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JGenericType genericComponentType = oracle.getType(MyList.class.getName()).isGenericType(); + + return oracle.getArrayType(genericComponentType); + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java index 26a3cf8..462da59 100644 --- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java
@@ -20,6 +20,7 @@ import com.google.gwt.dev.jdt.StaticCompilationUnitProvider; import com.google.gwt.dev.jdt.TypeOracleBuilder; import com.google.gwt.dev.jdt.URLCompilationUnitProvider; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; import junit.framework.TestCase; @@ -33,11 +34,18 @@ * Tests related to JClassType. See individual test methods to details. */ public class JClassTypeTest extends TestCase { + private final boolean logToConsole = false; + private final ModuleContext moduleContext = new ModuleContext(logToConsole + ? new PrintWriterTreeLogger() : TreeLogger.NULL, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); - public void testGetOverridableMethods() throws UnableToCompleteException, - TypeOracleException { + public JClassTypeTest() throws UnableToCompleteException { + } + + public void testGetOverridableMethods() throws TypeOracleException { TreeLogger logger = TreeLogger.NULL; - TypeOracle typeOracle = buildOracleFromTestPackage(logger); + TypeOracle typeOracle = moduleContext.getOracle(); + // TypeOracle typeOracle = buildOracleFromTestPackage(logger); String[] noParams = new String[0]; String[] intObjectParams = new String[] {"int", "java.lang.Object"}; @@ -224,7 +232,7 @@ // No files found. return; } - + for (int i = 0; i < files.length; i++) { File file = files[i]; if (file.isFile()) { @@ -301,54 +309,4 @@ } } } - - /** - * Looks in the package containing this class and uses it as an anchor for - * including all the classes under the "test" subpackage. - * - * TODO: This is not generalized yet, but it could be made reusable and put - * into TypeOracleBuilder. - * - * @return - * @throws URISyntaxException - * @throws UnableToCompleteException - * @throws MalformedURLException - */ - private TypeOracle buildOracleFromTestPackage(TreeLogger logger) - throws UnableToCompleteException { - Throwable caught; - try { - // Find the source path using this class as an anchor. - String className = getClass().getName(); - String resName = className.replace('.', '/') + ".java"; - URL location = getClass().getClassLoader().getResource(resName); - assertNotNull("Ensure that source is in classpath for: " + resName, - location); - String absPath = new File(new URI(location.toString())).getAbsolutePath(); - int sourcePathEntryLen = absPath.length() - resName.length(); - File sourcePathEntry = new File(absPath.substring(0, sourcePathEntryLen)); - - // Determine the starting package name. - int lastDot = className.lastIndexOf('.'); - String pkgName = (lastDot < 0 ? "test" : className.substring(0, lastDot) - + ".test"); - - // Create the builder to be filled in. - TypeOracleBuilder builder = new TypeOracleBuilder(); - - // Add java.lang.Object. - builder.addCompilationUnit(new StaticCompilationUnitProvider("java.lang", - "Object", "package java.lang; public class Object { }".toCharArray())); - - // Recursively walk the directories. - addCompilationUnitsInPath(builder, sourcePathEntry, pkgName); - return builder.build(logger); - } catch (URISyntaxException e) { - caught = e; - } catch (MalformedURLException e) { - caught = e; - } - logger.log(TreeLogger.ERROR, "Failed to build type oracle", caught); - throw new UnableToCompleteException(); - } }
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JDelegatingClassTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JDelegatingClassTypeTest.java new file mode 100644 index 0000000..f36935d --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JDelegatingClassTypeTest.java
@@ -0,0 +1,814 @@ +/* + * Copyright 2007 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 junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.util.Arrays; + +/** + * Base test cases for all {@link JDelegatingClassType}s. + */ +public abstract class JDelegatingClassTypeTest extends TestCase { + + protected static void assertArraysEqual(Object[] expected, Object[] actual) { + assertTrue("Expected: \n" + Arrays.toString(expected) + ",\n Actual: \n" + + Arrays.toString(actual), Arrays.equals(expected, actual)); + } + + protected static void validateAbstractMethodSubstitution( + JAbstractMethod preSubMethod, JAbstractMethod postSubMethod, + Substitution substitution) { + + assertEquals(preSubMethod.getName(), postSubMethod.getName()); + + assertEquals(preSubMethod.getModifierBits(), + postSubMethod.getModifierBits()); + + validateAnnotations(preSubMethod, postSubMethod); + + validateMetaData(preSubMethod, postSubMethod); + + JParameter[] preSubParams = preSubMethod.getParameters(); + JParameter[] postSubParams = postSubMethod.getParameters(); + + assertEquals(preSubParams.length, postSubParams.length); + + for (int j = 0; j < preSubParams.length; ++j) { + JParameter preSubParam = preSubParams[j]; + JParameter postSubParam = postSubParams[j]; + + validateAnnotations(preSubParam, postSubParam); + validateMetaData(preSubParam, postSubParam); + + assertEquals(substitution.getSubstitution(preSubParam.getType()), + postSubParam.getType()); + } + } + + protected static void validateAnnotations(HasAnnotations ha1, + HasAnnotations ha2) { + assertArraysEqual(ha1.getAnnotations(), ha2.getAnnotations()); + } + + protected static void validateConstructorSubstitutions( + JClassType preSubstitution, JClassType postSubstituion, + Substitution substitution) { + // Check the constructors + JConstructor[] preSubCtors = preSubstitution.getConstructors(); + JConstructor[] postSubCtors = postSubstituion.getConstructors(); + assertEquals(preSubCtors.length, postSubCtors.length); + for (int i = 0; i < preSubCtors.length; ++i) { + validateAbstractMethodSubstitution(preSubCtors[i], postSubCtors[i], + substitution); + } + } + + protected static void validateDeclaredAnnotations(HasAnnotations ha1, + HasAnnotations ha2) { + assertArraysEqual(ha1.getDeclaredAnnotations(), + ha2.getDeclaredAnnotations()); + } + + protected static void validateEquals(TypeOracle oracle, + JClassType[] expectedTypes, JClassType actualTypes[]) { + oracle.sort(expectedTypes); + oracle.sort(actualTypes); + + assertArraysEqual(expectedTypes, actualTypes); + } + + protected static void validateFieldSubstitutions(JClassType preSubstitution, + JClassType postSubstituion, Substitution substitution) { + // Check the fields + JField[] preSubfields = preSubstitution.getFields(); + JField[] postSubFields = postSubstituion.getFields(); + assertEquals(preSubfields.length, postSubFields.length); + for (int i = 0; i < preSubfields.length; ++i) { + JField postSubField = postSubstituion.getField(preSubfields[i].getName()); + assertNotNull(postSubField); + assertEquals(substitution.getSubstitution(preSubfields[i].getType()), + postSubField.getType()); + } + } + + protected static void validateFindConstructor(JClassType preSubstitution, + JClassType postSubstitution, Substitution substitution) { + + JConstructor[] constructors = preSubstitution.getConstructors(); + for (JConstructor constructor : constructors) { + JParameter[] params = constructor.getParameters(); + JType[] paramTypes = new JType[params.length]; + + for (int i = 0; i < params.length; ++i) { + paramTypes[i] = substitution.getSubstitution(params[i].getType()); + } + + assertNotNull(postSubstitution.findConstructor(paramTypes)); + } + } + + /** + * + */ + protected static void validateFindField(JClassType preSubstitution, + JClassType postSubstitution) { + JField[] fields = preSubstitution.getFields(); + for (JField field : fields) { + assertNotNull(postSubstitution.findField(field.getName())); + } + } + + protected static void validateFindMethod(JClassType preSubstitution, + JClassType postSubstitution, Substitution substitution) { + + JMethod[] methods = preSubstitution.getMethods(); + for (JMethod method : methods) { + JParameter[] params = method.getParameters(); + JType[] paramTypes = new JType[params.length]; + + for (int i = 0; i < params.length; ++i) { + paramTypes[i] = substitution.getSubstitution(params[i].getType()); + } + + assertNotNull(postSubstitution.findMethod(method.getName(), paramTypes)); + } + } + + protected static void validateGetConstructor(JClassType preSubstitution, + JClassType postSubstitution, Substitution substitution) + throws NotFoundException { + + JConstructor[] constructors = preSubstitution.getConstructors(); + for (JConstructor constructor : constructors) { + JParameter[] params = constructor.getParameters(); + JType[] paramTypes = new JType[params.length]; + + for (int i = 0; i < params.length; ++i) { + paramTypes[i] = substitution.getSubstitution(params[i].getType()); + } + + assertNotNull(postSubstitution.getConstructor(paramTypes)); + } + } + + /** + * + */ + protected static void validateGetField(JClassType preSubstitution, + JClassType postSubstitution) { + JField[] fields = preSubstitution.getFields(); + for (JField field : fields) { + assertNotNull(postSubstitution.getField(field.getName())); + } + } + + protected static void validateGetMethod(JClassType preSubstitution, + JClassType postSubstitution, Substitution substitution) + throws NotFoundException { + + JMethod[] methods = preSubstitution.getMethods(); + for (JMethod method : methods) { + JParameter[] params = method.getParameters(); + JType[] paramTypes = new JType[params.length]; + + for (int i = 0; i < params.length; ++i) { + paramTypes[i] = substitution.getSubstitution(params[i].getType()); + } + + assertNotNull(postSubstitution.getMethod(method.getName(), paramTypes)); + } + } + + protected static void validateGetOverloads(JClassType preSubstitution, + JClassType postSubstitution) { + JMethod[] methods = preSubstitution.getMethods(); + for (JMethod method : methods) { + assertEquals(preSubstitution.getOverloads(method.getName()).length, + postSubstitution.getOverloads(method.getName()).length); + } + } + + protected static void validateImplementedInterfaceSubstitution( + JClassType preSubstitution, JClassType postSubstituion, + Substitution substitution) { + JClassType[] preSubIntfs = preSubstitution.getImplementedInterfaces(); + JClassType[] postSubIntfs = postSubstituion.getImplementedInterfaces(); + + assertEquals(preSubIntfs.length, postSubIntfs.length); + + for (int i = 0; i < preSubIntfs.length; ++i) { + assertEquals(postSubIntfs[i], + substitution.getSubstitution(postSubIntfs[i])); + } + } + + protected static void validateMetaData(HasMetaData md1, HasMetaData md2) { + validateMetaDataTags(md1, md2); + + String[] md1TagNames = md1.getMetaDataTags(); + String[] md2TagNames = md2.getMetaDataTags(); + + for (int i = 0; i < md1TagNames.length; ++i) { + assertEquals(md1TagNames[i], md2TagNames[i]); + + String[][] md1TagValues = md1.getMetaData(md1TagNames[i]); + String[][] md2TagValues = md2.getMetaData(md2TagNames[i]); + + assertTrue(Arrays.deepEquals(md1TagValues, md2TagValues)); + } + } + + protected static void validateMetaDataTags(HasMetaData md1, HasMetaData md2) { + assertEquals(md1.getMetaDataTags().length, md2.getMetaDataTags().length); + } + + protected static void validateMethodSubstitution(JMethod preSubMethod, + JMethod postSubMethod, Substitution substitution) { + + assertEquals(substitution.getSubstitution(preSubMethod.getReturnType()), + postSubMethod.getReturnType()); + + validateAbstractMethodSubstitution(preSubMethod, postSubMethod, + substitution); + } + + protected static void validateMethodSubstitutions(JClassType preSubstitution, + JClassType postSubstituion, Substitution substitution) + throws NotFoundException { + // Check the methods + JMethod[] preSubMethods = preSubstitution.getMethods(); + JMethod[] postSubMethods = postSubstituion.getMethods(); + assertEquals(preSubMethods.length, postSubMethods.length); + + for (int i = 0; i < preSubMethods.length; ++i) { + JMethod preSubMethod = preSubMethods[i]; + + JParameter[] preSubParams = preSubMethod.getParameters(); + JType[] postSubParamTypes = new JType[preSubParams.length]; + for (int j = 0; j < preSubParams.length; ++j) { + postSubParamTypes[j] = substitution.getSubstitution(preSubParams[j].getType()); + } + JMethod postSubMethod = postSubstituion.getMethod(preSubMethod.getName(), + postSubParamTypes); + + validateMethodSubstitution(preSubMethod, postSubMethod, substitution); + } + } + + protected static void validateTypeSubstitution(JClassType preSubstitution, + JClassType postSubstituion, Substitution substitution) + throws NotFoundException { + if (preSubstitution.isGenericType() == null) { + return; + } + + assertEquals(preSubstitution.getModifierBits(), + postSubstituion.getModifierBits()); + + validateAnnotations(preSubstitution, postSubstituion); + + validateMetaData(preSubstitution, postSubstituion); + + assertEquals(preSubstitution.getName(), postSubstituion.getName()); + // assertEquals(preSubstitution.getSubstitution(substitution), + // postSubstituion); + + // Check superclass + JClassType superClass = preSubstitution.getSuperclass(); + if (superClass != null) { + validateTypeSubstitution(superClass, postSubstituion.getSuperclass(), + substitution); + } + + // Check interfaces + validateImplementedInterfaceSubstitution(preSubstitution, postSubstituion, + substitution); + + validateFieldSubstitutions(preSubstitution, postSubstituion, substitution); + + validateConstructorSubstitutions(preSubstitution, postSubstituion, + substitution); + + validateMethodSubstitutions(preSubstitution, postSubstituion, substitution); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findConstructor(com.google.gwt.core.ext.typeinfo.JType[])}. + */ + public void testFindConstructor() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateFindConstructor(baseType, testType, getSubstitution()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findField(java.lang.String)}. + */ + public void testFindField() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateFindField(baseType, testType); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findMethod(java.lang.String, com.google.gwt.core.ext.typeinfo.JType[])}. + */ + public void testFindMethod() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateFindMethod(baseType, testType, getSubstitution()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findNestedType(java.lang.String)}. + */ + public abstract void testFindNestedType() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getAnnotation(java.lang.Class)}. + */ + public void testGetAnnotation() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + Annotation[] annotations = baseType.getAnnotations(); + for (Annotation annotation : annotations) { + assertNotNull(testType.getAnnotation(annotation.annotationType())); + } + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getAnnotations()}. + */ + public void testGetAnnotations() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateAnnotations(baseType, testType); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getBaseType()}. + */ + public void testGetBaseType() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + assertNotNull(testType.getBaseType()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getCompilationUnit()}. + */ + public void testGetCompilationUnit() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(testType.getCompilationUnit(), baseType.getCompilationUnit()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getConstructor(com.google.gwt.core.ext.typeinfo.JType[])}. + */ + public void testGetConstructor() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + JConstructor[] constructors = baseType.getConstructors(); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getConstructors()}. + */ + public void testGetConstructors() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateConstructorSubstitutions(baseType, testType, getSubstitution()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getDeclaredAnnotations()}. + */ + public void testGetDeclaredAnnotations() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateDeclaredAnnotations(baseType, testType); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getEnclosingType()}. + */ + public abstract void testGetEnclosingType() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getErasedType()}. + */ + public void testGetErasedType() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.getErasedType(), testType.getErasedType()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getField(java.lang.String)}. + */ + public void testGetField() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateGetField(baseType, testType); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getFields()}. + */ + public void testGetFields() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateFieldSubstitutions(baseType, testType, getSubstitution()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getImplementedInterfaces()}. + */ + public void testGetImplementedInterfaces() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateImplementedInterfaceSubstitution(baseType, testType, + getSubstitution()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getJNISignature()}. + */ + public void testGetJNISignature() { + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getMetaData(java.lang.String)}. + */ + public void testGetMetaData() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateMetaData(baseType, testType); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getMetaDataTags()}. + */ + public void testGetMetaDataTags() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateMetaDataTags(baseType, testType); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getMethod(java.lang.String, com.google.gwt.core.ext.typeinfo.JType[])}. + */ + public void testGetMethod() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateGetMethod(baseType, testType, getSubstitution()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getMethods()}. + */ + public void testGetMethods() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateMethodSubstitutions(baseType, testType, getSubstitution()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getModifierBits()}. + */ + public void testGetModifierBits() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.getModifierBits(), testType.getModifierBits()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getName()}. + */ + public void testGetName() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.getName(), testType.getName()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getNestedType(java.lang.String)}. + */ + public abstract void testGetNestedType() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getNestedTypes()}. + */ + public abstract void testGetNestedTypes() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getOracle()}. + */ + public void testGetOracle() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.getOracle(), testType.getOracle()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getOverloads(java.lang.String)}. + */ + public void testGetOverloads() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + validateGetOverloads(baseType, testType); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getOverridableMethods()}. + */ + public abstract void testGetOverridableMethods() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getPackage()}. + */ + public void testGetPackage() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.getPackage(), testType.getPackage()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getSubtypes()}. + */ + public abstract void testGetSubtypes() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getSuperclass()}. + */ + public void testGetSuperclass() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.getSuperclass() != null, + testType.getSuperclass() != null); + + /* + * TODO: need to check that the super classes are consistent, if base super + * is generic then test type super should be parameterized with same super, + * etc. + */ + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAbstract()}. + */ + public void testIsAbstract() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isAbstract(), testType.isAbstract()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAnnotationPresent(java.lang.Class)}. + */ + public void testIsAnnotationPresent() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + Annotation[] annotations = baseType.getAnnotations(); + for (Annotation annotation : annotations) { + assertTrue(testType.isAnnotationPresent(annotation.annotationType())); + } + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isArray()}. + */ + public void testIsArray() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isArray(), testType.isArray()); + + // TODO: check parameterized arrays + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAssignableFrom(com.google.gwt.core.ext.typeinfo.JClassType)}. + */ + public abstract void testIsAssignableFrom() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAssignableTo(com.google.gwt.core.ext.typeinfo.JClassType)}. + */ + public abstract void testIsAssignableTo() throws NotFoundException; + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isClass()}. + */ + public void testIsClass() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isClass() != null, testType.isClass() != null); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isClassOrInterface()}. + */ + public void testIsClassOrInterface() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isClassOrInterface() != null, + testType.isClassOrInterface() != null); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isDefaultInstantiable()}. + */ + public void testIsDefaultInstantiable() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isDefaultInstantiable(), + testType.isDefaultInstantiable()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isEnum()}. + */ + public void testIsEnum() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isEnum() != null, testType.isEnum() != null); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isInterface()}. + */ + public void testIsInterface() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isInterface() != null, testType.isInterface() != null); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isLocalType()}. + */ + public void testIsLocalType() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isLocalType(), testType.isLocalType()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isMemberType()}. + */ + public void testIsMemberType() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isMemberType(), testType.isMemberType()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isPrimitive()}. + */ + public void testIsPrimitive() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertNull(testType.isPrimitive()); + assertNull(baseType.isPrimitive()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isPrivate()}. + */ + public void testIsPrivate() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isPrivate(), testType.isPrivate()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isProtected()}. + */ + public void testIsProtected() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isProtected(), testType.isProtected()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isPublic()}. + */ + public void testIsPublic() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isPublic(), testType.isPublic()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isStatic()}. + */ + public void testIsStatic() throws NotFoundException { + JDelegatingClassType testType = getTestType(); + JClassType baseType = testType.getBaseType(); + + assertEquals(baseType.isStatic(), testType.isStatic()); + } + + protected abstract Substitution getSubstitution() throws NotFoundException; + + protected abstract JDelegatingClassType getTestType() + throws NotFoundException; +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JEnumTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JEnumTypeTest.java new file mode 100644 index 0000000..fdc1b38 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JEnumTypeTest.java
@@ -0,0 +1,140 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.test.MyEnum; +import com.google.gwt.dev.cfg.ModuleDef; +import com.google.gwt.dev.cfg.ModuleDefLoader; + +import junit.framework.TestCase; + +/** + * Tests for {@link JEnumType}. + */ +public class JEnumTypeTest extends TestCase { + private final TreeLogger logger = TreeLogger.NULL; + + private ModuleDef moduleDef; + + private final TypeOracle typeOracle; + + public JEnumTypeTest() throws UnableToCompleteException, NotFoundException { + moduleDef = ModuleDefLoader.loadFromClassPath(logger, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); + typeOracle = moduleDef.getTypeOracle(logger); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JEnumType#getEnumConstants()}. + * + * @throws NotFoundException + */ + public void testGetEnumConstants() throws NotFoundException { + JClassType type = typeOracle.getType(MyEnum.class.getName()); + JEnumType enumType = type.isEnum(); + assertNotNull(enumType); + + JEnumConstant[] enumConstants = enumType.getEnumConstants(); + assertEquals(3, enumConstants.length); + + for (JEnumConstant enumConstant : enumConstants) { + assertEquals( + Integer.parseInt(enumConstant.getName().substring(3)), + enumConstant.getOrdinal()); + } + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JClassType#getFields()}. + * + * @throws NotFoundException + */ + public void testGetFields() throws NotFoundException { + JClassType type = typeOracle.getType(MyEnum.class.getName()); + JEnumType enumType = validateTypeIsEnum(type); + + assertEquals(5, enumType.getFields().length); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JClassType#getField(String)}. + * + * @throws NotFoundException + */ + public void testGetFieldString() throws NotFoundException { + JClassType type = typeOracle.getType(MyEnum.class.getName()); + + validateTypeIsEnum(type); + + type.getField("VAL0"); + type.getField("VAL1"); + type.getField("VAL2"); + type.getField("instanceField"); + type.getField("e"); + } + + /** + * Test method for {@link JEnumType#getConstructors()} + * + * @throws NotFoundException + * @throws NotFoundException + */ + public void testGetConstructors() throws NotFoundException { + JClassType type = typeOracle.getType(MyEnum.class.getName()); + JEnumType enumType = validateTypeIsEnum(type); + + assertEquals(1, enumType.getConstructors().length); + } + + /** + * Test method for {@link JEnumType#getMethods()} + * + * @throws NotFoundException + */ + public void testGetMethods() throws NotFoundException { + JClassType type = typeOracle.getType(MyEnum.class.getName()); + JEnumType enumType = validateTypeIsEnum(type); + + assertEquals(1, enumType.getMethods().length); + } + + /** + * Test method for {@link com.google.gwt.core.ext.typeinfo.JEnumType#isEnum()}. + * + * @throws NotFoundException + */ + public void testIsEnum() throws NotFoundException { + JClassType type = typeOracle.getType(MyEnum.class.getName()); + validateTypeIsEnum(type); + } + + private static JEnumType validateTypeIsEnum(JClassType type) + throws NotFoundException { + JEnumType maybeEnum = type.isEnum(); + assertNotNull(maybeEnum); + + JClassType enumType = type.getOracle().getType(Enum.class.getName()); + + assertTrue(enumType.isAssignableFrom(maybeEnum)); + + return maybeEnum; + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java new file mode 100644 index 0000000..c054387 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java
@@ -0,0 +1,99 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.test.GenericClass; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; + +import junit.framework.TestCase; + +/** + * Tests for {@link JGenericType}. + */ +public class JGenericTypeTest extends TestCase { + private final boolean logToConsole = false; + private final ModuleContext moduleContext = new ModuleContext(logToConsole + ? new PrintWriterTreeLogger() : TreeLogger.NULL, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); + + public JGenericTypeTest() throws UnableToCompleteException { + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JGenericType#getErasedType()}. + * + * @throws NotFoundException + */ + public void testGetErasedType() throws NotFoundException { + JGenericType genericClass = getTestType(); + + assertEquals(genericClass.getRawType(), genericClass.getErasedType()); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JGenericType#getRawType()}. + * + * @throws NotFoundException + */ + public void testGetRawType() throws NotFoundException { + JGenericType genericClass = getTestType(); + + JDelegatingClassTypeTest.validateTypeSubstitution(genericClass, + genericClass.getRawType(), new Substitution() { + public JType getSubstitution(JType type) { + return type.getErasedType(); + } + }); + } + + /** + * Test method for {@link + * com.google.gwt.core.ext.typeinfo.JGenericType#getTypeParameters()}. + * + * @throws NotFoundException + */ + public void testGetTypeParameters() throws NotFoundException { + JGenericType genericType = getTestType(); + JTypeParameter[] typeParameters = genericType.getTypeParameters(); + + assertEquals(1, typeParameters.length); + + JTypeParameter typeParameter = typeParameters[0]; + assertEquals("T", typeParameter.getName()); + + JBound bound = typeParameter.getBounds(); + assertNotNull(bound.isUpperBound()); + + JClassType[] bounds = bound.getBounds(); + assertEquals(1, bounds.length); + assertEquals(moduleContext.getOracle().getJavaLangObject(), bounds[0]); + } + + /** + * Returns the generic version of {@link GenericClass}. + */ + protected JGenericType getTestType() throws NotFoundException { + JClassType type = moduleContext.getOracle().getType( + GenericClass.class.getName()); + JGenericType genericType = type.isGenericType(); + assertNotNull(genericType); + return genericType; + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JParameterizedTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JParameterizedTypeTest.java new file mode 100644 index 0000000..50a06c4 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JParameterizedTypeTest.java
@@ -0,0 +1,401 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.test.Base; +import com.google.gwt.core.ext.typeinfo.test.Derived; +import com.google.gwt.core.ext.typeinfo.test.GenericClass; +import com.google.gwt.core.ext.typeinfo.test.MyCustomList; +import com.google.gwt.core.ext.typeinfo.test.MyIntegerList; +import com.google.gwt.core.ext.typeinfo.test.MyList; +import com.google.gwt.core.ext.typeinfo.test.GenericClass.GenericInnerClass; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Test for {@link JParameterizedType}. + */ +public class JParameterizedTypeTest extends JDelegatingClassTypeTest { + /** + * Helper for verifying parameterized substitutions. + */ + static class ParameterizedSubstitution implements Substitution { + private final JParameterizedType parameterizedType; + + public ParameterizedSubstitution(JParameterizedType parameterizedType) { + this.parameterizedType = parameterizedType; + } + + public JType getSubstitution(JType type) { + return type.getSubstitutedType(parameterizedType); + } + } + + private final JClassType integerType; + private final boolean logToConsole = false; + private final ModuleContext moduleContext = new ModuleContext(logToConsole + ? new PrintWriterTreeLogger() : TreeLogger.NULL, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); + + public JParameterizedTypeTest() throws UnableToCompleteException, + NotFoundException { + integerType = moduleContext.getOracle().getType(Integer.class.getName()); + } + + @Override + public void testFindNestedType() { + // TODO: complete this test method + } + + /** + * Checks that GenericClass<Integer> ends up with the correct substitutions. + * + * @throws NotFoundException + */ + public void testGenericClass_Integer() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JGenericType genericType = getGenericTestType(); + JClassType type = oracle.getParameterizedType(genericType, + new JClassType[] {integerType}); + JParameterizedType parameterizedType = type.isParameterized(); + + validateTypeSubstitution(genericType, parameterizedType, + new ParameterizedSubstitution(parameterizedType)); + } + + public void testGenericClass_LowerBoundWildcard() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JGenericType genericType = getGenericTestType(); + JWildcardType lowerBoundWildcard = oracle.getWildcardType(new JLowerBound( + new JClassType[] {integerType})); + + JClassType type = oracle.getParameterizedType(genericType, + new JClassType[] {lowerBoundWildcard}); + JParameterizedType parameterizedType = type.isParameterized(); + + validateTypeSubstitution(genericType, parameterizedType, + new ParameterizedSubstitution(parameterizedType)); + } + + public void testGenericClass_UnboundWildcard() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JGenericType genericType = getGenericTestType(); + JWildcardType upperBoundWildcard = oracle.getWildcardType(new JUpperBound( + new JClassType[] {oracle.getJavaLangObject()})); + + JClassType type = oracle.getParameterizedType(genericType, + new JClassType[] {upperBoundWildcard}); + JParameterizedType parameterizedType = type.isParameterized(); + + validateTypeSubstitution(genericType, parameterizedType, + new ParameterizedSubstitution(parameterizedType)); + } + + public void testGenericClass_UpperBoundWildcard() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JGenericType genericType = getGenericTestType(); + JWildcardType upperBoundWildcard = oracle.getWildcardType(new JUpperBound( + new JClassType[] {integerType})); + + JClassType type = oracle.getParameterizedType(genericType, + new JClassType[] {upperBoundWildcard}); + JParameterizedType parameterizedType = type.isParameterized(); + + validateTypeSubstitution(genericType, parameterizedType, + new ParameterizedSubstitution(parameterizedType)); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JParameterizedType#getEnclosingType()}. + * + * @throws NotFoundException + */ + @Override + public void testGetEnclosingType() throws NotFoundException { + JParameterizedType testType = getTestType(); + + // Check that GenericClass<Integer> is not nested + assertNull(testType.getEnclosingType()); + + /* + * Check that GenericClass<Integer>.GenericInnerClass<Boolean> has // + * GenericClass<Integer> as its // enclosing type + */ + JParameterizedType parameterizedInnerClass = getInnerParameterizedType(); + + assertEquals(testType, parameterizedInnerClass.getEnclosingType()); + } + + @Override + public void testGetNestedType() { + // TODO: complete this test method + } + + /** + * Test method for {@link + * com.google.gwt.core.ext.typeinfo.JParameterizedType#getNestedTypes()}. + * + * @throws NotFoundException + */ + @Override + public void testGetNestedTypes() throws NotFoundException { + JParameterizedType cut = getTestType(); + JParameterizedType innerCut = getInnerParameterizedType(); + + // Check that inner parameterized types don't appear in the parent's nested + // type set + assertEquals(0, cut.getNestedTypes().length); + + try { + cut.getNestedType(innerCut.getSimpleSourceName()); + fail("Type " + cut.getQualifiedSourceName() + + " should report that it has no nested types"); + } catch (NotFoundException ex) { + // Expected to get here + } + } + + @Override + public void testGetOverridableMethods() throws NotFoundException { + // Tested via testOverridableMethods_Base, testOverridableMethods_Derived, + // testOverridableMethods_Derived_Integer + } + + /** + * Tests the subtypes of MyList<Integer>. These should be: + * <ul> + * <li><code>MyIntegerList</code></li> + * <li><code>MyCustomList<? extends Serializable, Integer></code></li> + * </ul> + * + * @throws NotFoundException + */ + @Override + public void testGetSubtypes() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JGenericType genericType = oracle.getType(MyList.class.getName()).isGenericType(); + + JParameterizedType parameterizedType = oracle.getParameterizedType( + genericType, new JClassType[] {integerType}); + JClassType[] actualSubtypes = parameterizedType.getSubtypes(); + + JGenericType myCustomListType = oracle.getType(MyCustomList.class.getName()).isGenericType(); + JParameterizedType parameterizedMyCustomList = oracle.getParameterizedType( + myCustomListType, new JClassType[] { + oracle.getWildcardType(new JUpperBound( + oracle.getType(Serializable.class.getName()))), integerType}); + JClassType[] expected = { + oracle.getType(MyIntegerList.class.getName()), + parameterizedMyCustomList + }; + + validateEquals(oracle, expected, actualSubtypes); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JParameterizedType#isAssignableFrom(JClassType)}. + */ + @Override + public void testIsAssignableFrom() throws NotFoundException { + // Check that raw types can be assigned to a parameterized type + JParameterizedType testType = getTestType(); + JClassType rawType = testType.getRawType(); + + assertTrue(testType.isAssignableFrom(rawType)); + + TypeOracle oracle = moduleContext.getOracle(); + JGenericType genericList = (JGenericType) oracle.getType(List.class.getName()); + + JWildcardType unboundWildcard = oracle.getWildcardType(new JUpperBound( + oracle.getJavaLangObject())); + JWildcardType numUpperBoundWildcard = oracle.getWildcardType(new JUpperBound( + oracle.getType(Number.class.getName()))); + + // List<?> should be assignable from List<? extends Number> + JParameterizedType unboundList = oracle.getParameterizedType(genericList, + new JClassType[] {unboundWildcard}); + JParameterizedType numUpperBoundList = oracle.getParameterizedType( + genericList, new JClassType[] {numUpperBoundWildcard}); + assertTrue(unboundList.isAssignableFrom(numUpperBoundList)); + assertFalse(numUpperBoundList.isAssignableFrom(unboundList)); + + // List<? extends Number> should be assignable from List<? extends Integer> + JWildcardType intUpperBoundWildcard = oracle.getWildcardType(new JUpperBound( + integerType)); + + JParameterizedType intUpperBoundList = oracle.getParameterizedType( + genericList, new JClassType[] {intUpperBoundWildcard}); + assertTrue(numUpperBoundList.isAssignableFrom(intUpperBoundList)); + assertFalse(intUpperBoundList.isAssignableFrom(numUpperBoundList)); + + // List<? super Integer> should be assignable from List<? super Number> + JWildcardType numLowerBoundWildcard = oracle.getWildcardType(new JLowerBound( + oracle.getType(Number.class.getName()))); + JWildcardType intLowerBoundWildcard = oracle.getWildcardType(new JLowerBound( + integerType)); + + JParameterizedType numLowerBoundList = oracle.getParameterizedType( + genericList, new JClassType[] {numLowerBoundWildcard}); + JParameterizedType intLowerBoundList = oracle.getParameterizedType( + genericList, new JClassType[] {intLowerBoundWildcard}); + + assertTrue(intLowerBoundList.isAssignableFrom(numLowerBoundList)); + assertFalse(numLowerBoundList.isAssignableFrom(intLowerBoundList)); + } + + /** + * Test method for + * {@link com.google.gwt.core.ext.typeinfo.JParameterizedType#isAssignableTo(JClassType)}. + */ + @Override + public void testIsAssignableTo() { + // TODO: + } + + public void testOverridableMethods_Base() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType type = oracle.getType(Base.class.getName()); + JGenericType genericType = type.isGenericType(); + assertNotNull(genericType); + + List<JMethod> expected = new ArrayList<JMethod>( + Arrays.asList(type.getOverloads("m"))); + List<JMethod> actual = new ArrayList<JMethod>( + Arrays.asList(type.getOverridableMethods())); + + validateOverridableMethods(expected, actual, true); + } + + public void testOverridableMethods_Derived() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType type = oracle.getType(Derived.class.getName()); + JGenericType genericType = type.isGenericType(); + assertNotNull(genericType); + + JClassType supertype = type.getSuperclass(); + JParameterizedType paramType = supertype.isParameterized(); + // JGenericType genericSuperType = paramType.getBaseType().isGenericType(); + assertNotNull(paramType); + + List<JMethod> expected = new ArrayList<JMethod>(); + expected.addAll(Arrays.asList(genericType.getOverloads("m"))); + expected.add(paramType.getMethod("m", + new JType[] {paramType.getTypeArgs()[0]})); + + List<JMethod> actual = new ArrayList<JMethod>( + Arrays.asList(type.getOverridableMethods())); + + validateOverridableMethods(expected, actual, true); + } + + public void testOverridableMethods_Derived_Integer() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType type = oracle.getType(Derived.class.getName()); + JGenericType genericType = type.isGenericType(); + assertNotNull(genericType); + + JParameterizedType paramType = oracle.getParameterizedType(genericType, + new JClassType[] {integerType}); + + List<JMethod> expected = new ArrayList<JMethod>(); + expected.addAll(Arrays.asList(paramType.getOverloads("m"))); + + List<JMethod> actual = new ArrayList<JMethod>( + Arrays.asList(paramType.getOverridableMethods())); + + validateOverridableMethods(expected, actual, true); + } + + /** + * Returns the <code>TypeOracle</code> type for {@link GenericClass}. + * + * @return <code>TypeOracle</code> type for {@link GenericClass} + * @throws NotFoundException + */ + protected JGenericType getGenericTestType() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType type = oracle.getType(GenericClass.class.getName()); + assertNotNull(type.isGenericType()); + return type.isGenericType(); + } + + @Override + protected Substitution getSubstitution() throws NotFoundException { + return new ParameterizedSubstitution(getTestType()); + } + + @Override + protected JParameterizedType getTestType() throws NotFoundException { + JGenericType type = getGenericTestType(); + + return moduleContext.getOracle().getParameterizedType(type, null, + new JClassType[] {integerType}); + } + + /** + * Returns the type for GenericClass<Integer>.GenericInnerClass<Boolean>. + * + * @throws NotFoundException + * @return type for GenericClass<Integer>.GenericInnerClass<Boolean> + */ + private JParameterizedType getInnerParameterizedType() + throws NotFoundException { + JParameterizedType cut = getTestType(); + TypeOracle oracle = moduleContext.getOracle(); + JGenericType innerGenericClass = cut.getBaseType().getNestedType( + GenericInnerClass.class.getSimpleName()).isGenericType(); + + JClassType booleanType = oracle.getType(Boolean.class.getName()); + + /* + * Check that GenericClass<Integer>.GenericInnerClass<Boolean> has + * GenericClass<Integer> as its enclosing type + */ + // + JParameterizedType parameterizedInnerClass = oracle.getParameterizedType( + innerGenericClass, cut, new JClassType[] {booleanType}); + + return parameterizedInnerClass; + } + + private void validateOverridableMethods(List<JMethod> expected, + List<JMethod> actual, boolean addObjectMethods) { + Set<JMethod> expectedMethods = new HashSet<JMethod>(); + expectedMethods.addAll(expected); + if (addObjectMethods) { + TypeOracle oracle = moduleContext.getOracle(); + expectedMethods.addAll(Arrays.asList(oracle.getJavaLangObject().getMethods())); + } + + for (JMethod method : actual) { + assertEquals("Method " + method.getReadableDeclaration() + " from type " + + method.getEnclosingType().getQualifiedSourceName() + + " was not expected", true, expectedMethods.remove(method)); + } + + assertTrue(expectedMethods.isEmpty()); + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JRawTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JRawTypeTest.java new file mode 100644 index 0000000..b1f4425 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JRawTypeTest.java
@@ -0,0 +1,110 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.test.MyCustomList; +import com.google.gwt.core.ext.typeinfo.test.MyIntegerList; +import com.google.gwt.core.ext.typeinfo.test.MyList; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; + +import java.util.ArrayList; + +/** + * Test for {@link JRawType}. + */ +public class JRawTypeTest extends JDelegatingClassTypeTest { + private final boolean logToConsole = false; + + private final ModuleContext moduleContext = new ModuleContext(logToConsole + ? new PrintWriterTreeLogger() : TreeLogger.NULL, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); + + public JRawTypeTest() throws UnableToCompleteException { + } + + @Override + public void testFindNestedType() { + // TODO Auto-generated method stub + } + @Override + public void testGetEnclosingType() { + // TODO Auto-generated method stub + } + @Override + public void testGetNestedType() { + // TODO Auto-generated method stub + } + + @Override + public void testGetNestedTypes() { + // TODO Auto-generated method stub + } + + @Override + public void testGetOverridableMethods() { + // TODO Auto-generated method stub + } + + @Override + public void testGetSubtypes() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType testType = oracle.getType(MyList.class.getName()); + JGenericType genericTestType = testType.isGenericType(); + assertNotNull(genericTestType); + + JRawType rawTestType = genericTestType.getRawType(); + JClassType[] expectedTypes = new JClassType[] { + oracle.getType(MyCustomList.class.getName()).isGenericType().getRawType(), + oracle.getType(MyIntegerList.class.getName()) + }; + JClassType[] actualSubtypes = rawTestType.getSubtypes(); + + validateEquals(oracle, expectedTypes, actualSubtypes); + } + + @Override + public void testIsAssignableFrom() throws NotFoundException { + JRawType rawType = getTestType(); + assertTrue(rawType.isAssignableFrom(rawType.getBaseType())); + } + + @Override + public void testIsAssignableTo() throws NotFoundException { + JRawType rawType = getTestType(); + assertTrue(rawType.getBaseType().isAssignableTo(rawType)); + } + + @Override + protected Substitution getSubstitution() throws NotFoundException { + return new Substitution() { + public JType getSubstitution(JType type) { + return type.getErasedType(); + } + }; + } + + /** + * Returns the RawType for {@link ArrayList}. + */ + @Override + protected JRawType getTestType() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType testType = oracle.getType(ArrayList.class.getName()); + return testType.isGenericType().getRawType(); + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java new file mode 100644 index 0000000..0fb9438 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java
@@ -0,0 +1,143 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.test.GenericClass; +import com.google.gwt.core.ext.typeinfo.test.GenericSubclass; +import com.google.gwt.core.ext.typeinfo.test.MyCustomList; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; + +import java.util.Arrays; + +/** + * Tests for {@link JTypeParameter}. + */ +public class JTypeParameterTest extends JDelegatingClassTypeTest { + private final boolean logToConsole = false; + private final ModuleContext moduleContext = new ModuleContext(logToConsole + ? new PrintWriterTreeLogger() : TreeLogger.NULL, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); + + public JTypeParameterTest() throws UnableToCompleteException { + } + + @Override + public void testFindConstructor() { + } + + @Override + public void testFindNestedType() { + } + + @Override + public void testGetConstructors() { + } + + @Override + public void testGetEnclosingType() throws NotFoundException { + JTypeParameter testType = getTestType(); + assertEquals( + moduleContext.getOracle().getType(GenericClass.class.getName()), + testType.getDeclaringClass()); + } + + @Override + public void testGetName() throws NotFoundException { + assertEquals("T", getTestType().getName()); + } + + @Override + public void testGetNestedType() { + } + + @Override + public void testGetNestedTypes() throws NotFoundException { + JTypeParameter testType = getTestType(); + + assertTrue(Arrays.deepEquals(testType.getNestedTypes(), + testType.getFirstBound().getNestedTypes())); + } + + @Override + public void testGetOverridableMethods() throws NotFoundException { + JTypeParameter testType = getTestType(); + + assertTrue(Arrays.deepEquals(testType.getOverridableMethods(), + testType.getFirstBound().getOverridableMethods())); + } + + @Override + public void testGetSubtypes() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType testType = oracle.getType(MyCustomList.class.getName()); + JGenericType genericType = testType.isGenericType(); + JTypeParameter[] typeParameters = genericType.getTypeParameters(); + JTypeParameter typeParameter = typeParameters[0]; + + JClassType[] expected = new JClassType[] { + /* + * TODO: Re-eneable this once java.io.Serializable is added to the JRE + * + * emulation classes oracle.getType(Integer.class.getName()), + * oracle.getType(Float.class.getName()), + * oracle.getType(Short.class.getName()), + * oracle.getType(Double.class.getName()), + * oracle.getType(Number.class.getName()), + * oracle.getType(Long.class.getName()), + * oracle.getType(Byte.class.getName()), + */ + }; + validateEquals(oracle, expected, typeParameter.getSubtypes()); + } + + @Override + public void testIsAssignableFrom() throws NotFoundException { + JTypeParameter testType = getTestType(); + assertTrue(testType.isAssignableFrom(moduleContext.getOracle().getJavaLangObject())); + } + + @Override + public void testIsAssignableTo() throws NotFoundException { + JTypeParameter testType = getTestType(); + assertTrue(testType.isAssignableTo(moduleContext.getOracle().getJavaLangObject())); + } + + @Override + protected Substitution getSubstitution() { + return new Substitution() { + public JType getSubstitution(JType type) { + return type; + } + }; + } + + /* + * NOTE: This method returns the type parameter T from the GenericClass<T> + * type. + */ + @Override + protected JTypeParameter getTestType() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType testType = oracle.getType(GenericClass.class.getName()); + JGenericType genericTestType = testType.isGenericType(); + assertNotNull(genericTestType); + JTypeParameter[] typeParameters = genericTestType.getTypeParameters(); + assertTrue(typeParameters.length > 0); + return typeParameters[0]; + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JWildcardTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JWildcardTypeTest.java new file mode 100644 index 0000000..becea26 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JWildcardTypeTest.java
@@ -0,0 +1,238 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.test.CA; +import com.google.gwt.core.ext.typeinfo.test.CB; +import com.google.gwt.core.ext.typeinfo.test.CC; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Test for {@link JWildcardType}. + */ +public class JWildcardTypeTest extends JDelegatingClassTypeTest { + private final boolean logToConsole = false; + private final ModuleContext moduleContext = new ModuleContext(logToConsole + ? new PrintWriterTreeLogger() : TreeLogger.NULL, + "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); + + public JWildcardTypeTest() throws UnableToCompleteException { + } + + @Override + public void testFindConstructor() { + // Wildcard types do not have constructors + } + + @Override + public void testFindNestedType() { + // Wildcard do not have nested types... + } + + @Override + public void testGetConstructors() { + } + + @Override + public void testGetEnclosingType() { + // Wildcard do not have nested types... + } + + @Override + public void testGetNestedType() { + // No nested types + } + + @Override + public void testGetNestedTypes() { + // No nested types + } + + @Override + public void testGetOverridableMethods() { + // No overridable methods + } + + @Override + public void testGetSubtypes() { + // Tested by testGetSubtypes_LowerBound() and testGetSubtypes_UpperBound() + } + + public void testGetSubtypes_LowerBound() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + // <? super Number> + JWildcardType lowerBoundWildcard = oracle.getWildcardType(new JLowerBound( + oracle.getType(Number.class.getName()))); + JClassType[] subtypes = lowerBoundWildcard.getSubtypes(); + assertEquals(0, subtypes.length); +// assertEquals(oracle.getJavaLangObject(), subtypes[0]); + } + + public void testGetSubtypes_UpperBound() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + // <? extends CA> + JWildcardType upperBoundWildcard = oracle.getWildcardType(new JUpperBound( + oracle.getType(CA.class.getName()))); + + JClassType[] expected = new JClassType[] { + oracle.getType(CB.class.getName()), oracle.getType(CC.class.getName())}; + Set<JClassType> expectedSet = new HashSet<JClassType>(); + expectedSet.addAll(Arrays.asList(expected)); + + JClassType[] actual = upperBoundWildcard.getSubtypes(); + assertEquals(expectedSet.size(), actual.length); + + for (int i = 0; i < actual.length; ++i) { + expectedSet.remove(actual[i]); + } + assertTrue(expectedSet.isEmpty()); + } + + @Override + public void testIsAssignableFrom() { + // Covered by the different testIsAssignableFrom*() variants below. + } + + /** + * Tests that <? extends Number> is assignable from <? extends Integer> and + * that the reverse is not <code>true</code>. + */ + public void testIsAssignableFrom_Extends_Number_To_Extends_Integer() + throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType numberType = oracle.getType(Number.class.getName()); + JClassType integerType = oracle.getType(Integer.class.getName()); + + JUpperBound numberBound = new JUpperBound(numberType); + JUpperBound integerBound = new JUpperBound(integerType); + + JWildcardType numberWildcard = oracle.getWildcardType(numberBound); + JWildcardType integerWildcard = oracle.getWildcardType(integerBound); + + assertTrue(numberWildcard.isAssignableFrom(integerWildcard)); + assertFalse(integerWildcard.isAssignableFrom(numberWildcard)); + } + + /** + * Tests that <? extends Number> is assignable from <? extends Integer> and + * that the reverse is not <code>true</code>. + */ + public void testIsAssignableFrom_Extends_Object_From_Super_Object() + throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + + JClassType javaLangObject = oracle.getJavaLangObject(); + JLowerBound lowerBound = new JLowerBound(javaLangObject); + JUpperBound upperBound = new JUpperBound(javaLangObject); + + JWildcardType lowerWildcard = oracle.getWildcardType(lowerBound); + JWildcardType upperWildcard = oracle.getWildcardType(upperBound); + + assertTrue(upperWildcard.isAssignableFrom(lowerWildcard)); + assertFalse(lowerWildcard.isAssignableFrom(upperWildcard)); + } + + /** + * Tests that <? super Integer> is assignable from <? super Number> and that + * the reverse is not <code>true</code>. + */ + public void testIsAssignableFrom_Super_Integer_From_Super_Number() + throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType numberType = oracle.getType(Number.class.getName()); + JClassType integerType = oracle.getType(Integer.class.getName()); + + JLowerBound numberBound = new JLowerBound(numberType); + JLowerBound integerBound = new JLowerBound(integerType); + + JWildcardType numberWildcard = oracle.getWildcardType(numberBound); + JWildcardType integerWildcard = oracle.getWildcardType(integerBound); + + assertFalse(numberWildcard.isAssignableFrom(integerWildcard)); + assertTrue(integerWildcard.isAssignableFrom(numberWildcard)); + } + + /** + * Tests that <? super Number> is assignable to <? super Integer> and that the + * reverse is not <code>true</code>. + */ + public void testIsAssignableFrom_Super_Number_To_Super_Integer() + throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType numberType = oracle.getType(Number.class.getName()); + JClassType integerType = oracle.getType(Integer.class.getName()); + + JLowerBound numberBound = new JLowerBound(numberType); + JLowerBound integerBound = new JLowerBound(integerType); + + JWildcardType numberWildcard = oracle.getWildcardType(numberBound); + JWildcardType integerWildcard = oracle.getWildcardType(integerBound); + + assertFalse(numberWildcard.isAssignableTo(integerWildcard)); + assertTrue(integerWildcard.isAssignableTo(numberWildcard)); + } + + @Override + public void testIsAssignableTo() { + } + + /** + * Tests that <? extends Integer> is assignable to <? extends Number> and that + * the reverse is not <code>true</code>. + */ + public void testIsAssignableTo_Extends_Integer_To_Extends_Number() + throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + JClassType numberType = oracle.getType(Number.class.getName()); + JClassType integerType = oracle.getType(Integer.class.getName()); + + JUpperBound numberBound = new JUpperBound(numberType); + JUpperBound integerBound = new JUpperBound(integerType); + + JWildcardType numberWildcard = oracle.getWildcardType(numberBound); + JWildcardType integerWildcard = oracle.getWildcardType(integerBound); + + assertTrue(integerWildcard.isAssignableTo(numberWildcard)); + assertFalse(numberWildcard.isAssignableTo(integerWildcard)); + } + + @Override + protected Substitution getSubstitution() { + return new Substitution() { + public JType getSubstitution(JType type) { + return type; + } + }; + } + + public void testGetMethods() throws NotFoundException { + super.testGetMethods(); + } + + + @Override + protected JWildcardType getTestType() throws NotFoundException { + TypeOracle oracle = moduleContext.getOracle(); + return oracle.getWildcardType(new JUpperBound( + oracle.getType(Number.class.getName()))); + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/ModuleContext.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/ModuleContext.java new file mode 100644 index 0000000..acb8b2f --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/ModuleContext.java
@@ -0,0 +1,43 @@ +/* + * Copyright 2007 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.core.ext.UnableToCompleteException; +import com.google.gwt.dev.cfg.ModuleDef; +import com.google.gwt.dev.cfg.ModuleDefLoader; + +/** + * Helper for loading modules from the classpath. + */ +class ModuleContext { + private final TypeOracle oracle; + private final ModuleDef moduleDef; + + ModuleContext(TreeLogger logger, String moduleName) + throws UnableToCompleteException { + moduleDef = ModuleDefLoader.loadFromClassPath(logger, moduleName); + oracle = moduleDef.getTypeOracle(logger); + } + + public TypeOracle getOracle() { + return oracle; + } + + public ModuleDef getModule() { + return moduleDef; + } +} \ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleGenericsSupportTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleGenericsSupportTest.java index d1b4f93..e69de29 100644 --- a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleGenericsSupportTest.java +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleGenericsSupportTest.java
@@ -1,49 +0,0 @@ -/* - * Copyright 2007 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.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.typeinfo.test.GenericSubclass; -import com.google.gwt.dev.cfg.ModuleDef; -import com.google.gwt.dev.cfg.ModuleDefLoader; - -import junit.framework.TestCase; - -/** - * Test cases for the {@link TypeOracle}'s and TypeOracleBuilder support for - * generics. - */ -public class TypeOracleGenericsSupportTest extends TestCase { - static { - ModuleDefLoader.setEnableCachingModules(true); - } - - private final TreeLogger logger = TreeLogger.NULL; - private ModuleDef moduleDef; - - private final TypeOracle typeOracle; - - public TypeOracleGenericsSupportTest() throws UnableToCompleteException { - moduleDef = ModuleDefLoader.loadFromClassPath(logger, - "com.google.gwt.core.ext.typeinfo.TypeOracleTest"); - typeOracle = moduleDef.getTypeOracle(logger); - } - - public void test() throws NotFoundException { - JClassType type = typeOracle.getType(GenericSubclass.class.getName()); - } -}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleSuite.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleSuite.java new file mode 100644 index 0000000..307e7da --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleSuite.java
@@ -0,0 +1,35 @@ +/* + * Copyright 2007 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 junit.framework.Test; +import junit.framework.TestSuite; + +public class TypeOracleSuite extends TestSuite { + public static Test suite() { + TestSuite suite = new TestSuite("Test suite for TypeOracle"); + suite.addTestSuite(AnnotationsTest.class); + suite.addTestSuite(JArrayTypeTest.class); + suite.addTestSuite(JClassTypeTest.class); + suite.addTestSuite(JEnumTypeTest.class); + suite.addTestSuite(JGenericTypeTest.class); + suite.addTestSuite(JParameterizedTypeTest.class); + suite.addTestSuite(JRawTypeTest.class); + suite.addTestSuite(JTypeParameterTest.class); + suite.addTestSuite(JWildcardTypeTest.class); + return suite; + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/Base.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/Base.java new file mode 100644 index 0000000..8300078 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/Base.java
@@ -0,0 +1,36 @@ +/* + * Copyright 2007 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.test; + +import java.io.Serializable; + +/** + * Class used to test + * {@link com.google.gwt.core.ext.typeinfo.JClassType#getOverridableMethods()}. + */ +public class Base<T> { + void m(T t) { + System.out.println("Base<T>.m(T)"); + } + + <N extends Number> void m(N n) { + System.out.println("Base<T>.m(N)"); + } + + static <N extends Serializable> void serialize(N n) { + System.out.println("Base<T>.<N extends Serializable>.serialize(N)"); + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/Derived.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/Derived.java new file mode 100644 index 0000000..1cf20c7 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/Derived.java
@@ -0,0 +1,62 @@ +/* + * Copyright 2007 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.test; + +import java.io.Serializable; + +/** + * Class used to test + * {@link com.google.gwt.core.ext.typeinfo.JClassType#getOverridableMethods()}. + * + * Derived<T> Overridable Methods (methods from java.lang.Object not shown): + * Derived<T>.m(Integer) + * Derived<T>.m(Number) + * Derived<T>.m(Integer) + * Derived<T>.<T extends Serializable> void m(T t) + */ +public class Derived<T> extends Base<T> { + public void m(Integer i) { + System.out.println("Derived<T>.m(Integer)"); + } // new Overload + + /** + * Overrides Base<T>.m(T) + * + * NOTE: this is commented out because JDT 3.1 will report it as an error, + * even though javac 1.5 allows this. + */ +// @Override +// public void m(Object t) { +// System.out.println("Derived<T>.m(Object)"); +// } // + + /** + * Overrides Base<T>.<N extends Number>.m(N) + */ + @Override + public void m(Number n) { + System.out.println("Derived<T>.m(Number)"); + } // overrides m(N) + + /** + * Overloads m + * @param <T> + * @param t + */ + public <T extends Serializable> void m(T t) { + System.out.println("Derived<T>.<T extends Serializable>.m(T)"); + } +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java index 085a567..047b3af 100644 --- a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClass.java
@@ -15,21 +15,106 @@ */ package com.google.gwt.core.ext.typeinfo.test; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + /** - * + * Generic class. + * + * @param <T> + * + * NOTE: It seems that the JDT 3.1 will not allow: GenericClass<Integer> if the + * definition of GenericClass is as follows: class GenericClass<T extends + * Serializable & Comparable<T>> implements Comparable<T> { ... } */ -public class GenericClass<T> { - T t; - +public class GenericClass<T> implements Comparable<T> { + /** + * Non-static, generic inner class. + * + * @param <U> + */ + public class GenericInnerClass<U> { + T t2; + U u2; + } + + /** + * This class is not technically a generic class although it has a member that + * references a type parameter from its enclosing type. + */ + public class NonGenericInnerClass { + T t3; + } + + public class Foo { + public class Bar { + T t4; + } + } + + /** + * Field of an inner class that is enclosed in a parameterized type. + */ + GenericClass<Integer>.NonGenericInnerClass nonGenericInnerClassField; + + /** + * NOTE: The following is disabled because it violates an assumption in TOB + * line 1228. + */ +// GenericClass.NonGenericInnerClass rawNonGenericInnerClassField; + + GenericClass<Integer>.Foo.Bar wtf; + + Class rawClazzField; + + /** + * Field of a raw type. + */ + ArrayList rawFieldType; + + /** + * Field of a type parameter type. + */ + T typeParameterField; + + /** + * Parameterized with a array type argument. + */ + List<T[]> parameterizedListField; + + public GenericClass() { + } + public GenericClass(T t) { - this.t = t; + this.typeParameterField = t; } - + + public int compareTo(T o) { + // TODO Auto-generated method stub + return 0; + } + public T getT() { - return t; + return typeParameterField; } - + + /* + * Generic method + */ + public <U> U max(Collection<U> collection) { + return collection.iterator().next(); + } + + /* + * Generic method + */ + public <U> U min(Collection<U> collection) { + return collection.iterator().next(); + } + public void setT(T t) { - this.t = t; + this.typeParameterField = t; } -} +} \ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java index 056313a..23187a6 100644 --- a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericSubclass.java
@@ -16,13 +16,18 @@ package com.google.gwt.core.ext.typeinfo.test; /** - * + * Test a generic class that extends a generic class. */ public class GenericSubclass<U> extends GenericClass<U> { - // Explore what JDT does when there is a parameterized type GenericClass<Integer> child; - + public GenericSubclass(U t) { super(t); } + + // TODO: This triggers a name clash problem with JDT 3.1 but not with JDT + // 3.3.0 or with javac 1.5.06. + // public void setT(Object t) { + // // this should override GenericClass<U>.setT(T t); + // } }
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyCustomList.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyCustomList.java new file mode 100644 index 0000000..53ce7ed --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyCustomList.java
@@ -0,0 +1,26 @@ +/* + * Copyright 2007 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.test; + +import java.io.Serializable; + +/** + * Used to test wildcard card expansion when looking for List<Integer> + * subtypes. + */ +public class MyCustomList<T extends Serializable & Comparable<T>, U> extends + MyList<U> { +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyEnum.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyEnum.java new file mode 100644 index 0000000..d703461 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyEnum.java
@@ -0,0 +1,56 @@ +/* + * Copyright 2007 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.test; + +/** + * Enumerated type used in the + * {@link com.google.gwt.core.ext.typeinfo.JEnumTypeTest}. + * + * NOTE: do not reorder the enumerated values + */ +public enum MyEnum { + @Deprecated + VAL0(-1) { + @Override + public int getId() { + return instanceField; + } + }, + + VAL1(-2) { + @Override + public int getId() { + return instanceField; + } + }, + + VAL2(-3) { + @Override + public int getId() { + return instanceField; + } + }; + + MyEnum(int instanceField) { + this.instanceField = instanceField; + } + + public final int instanceField; + + public static final MyEnum e = VAL2; + + public abstract int getId(); +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyIntegerList.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyIntegerList.java new file mode 100644 index 0000000..0d1e559 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyIntegerList.java
@@ -0,0 +1,22 @@ +/* + * Copyright 2007 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.test; + +/** + * Used to test that this type gets picked up as a subtype of List<Integer>. + */ +public class MyIntegerList extends MyList<Integer> { +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyList.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyList.java new file mode 100644 index 0000000..94fa2f1 --- /dev/null +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/MyList.java
@@ -0,0 +1,22 @@ +/* + * Copyright 2007 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.test; + +/** + * Used for testing parameterized subtypes. + */ +public class MyList<T> { +}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/NonGenericSubclass.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/NonGenericSubclass.java index 44413a4..03f98fb 100644 --- a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/NonGenericSubclass.java +++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/NonGenericSubclass.java
@@ -16,7 +16,7 @@ package com.google.gwt.core.ext.typeinfo.test; /** - * + * Test a non-generic class that extends a parameterized type. */ public class NonGenericSubclass extends GenericClass<Integer> { /** @@ -24,6 +24,12 @@ */ public NonGenericSubclass(Integer t) { super(t); - // TODO Auto-generated constructor stub + } + + + /** + * Tests overloading of generic methods. + */ + public void setT(Integer t) { } }