Previously, the TypeOracleBuilder would throw a NPE on declarations of the form:
public class <C extends AnotherClass<M>, M extends AThirdClass> MyClass {
...
}
A similar declaration for a generic method would cause the same problem. To fix this issue, type parameters on a generic type are constructed (along with JClassTypes, JGenericTypes, etc..) on the first pass through the AST (i.e. the 'process' phase). However, they are only partially constructed. The type bounds on a type parameter are created during the second pass through the AST (the 'resolve' phase).
Performed a bit of cleanup in TypeOracleBuilder by getting rid of the bifurcated methods for resolving type parameters on generic types vs. abstract methods. This was done by using an interface common to both types - HasTypeParameters.
Modified JTypeParameter.getEnclosingType() to always return null, since type parameters do not have enclosing types.
Patch by: rdayal, mmendez
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1739 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 e7f8b98..d8c6fa9 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -53,7 +53,8 @@
// Only the builder can construct
JAbstractMethod(String name, int declStart, int declEnd, int bodyStart,
int bodyEnd,
- Map<Class<? extends Annotation>, Annotation> declaredAnnotations) {
+ Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
+ JTypeParameter[] jtypeParameters) {
this.name = name;
this.declStart = declStart;
this.declEnd = declEnd;
@@ -61,12 +62,14 @@
this.bodyEnd = bodyEnd;
annotations = new Annotations();
annotations.addAnnotations(declaredAnnotations);
+
+ if (jtypeParameters != null) {
+ for (JTypeParameter jtypeParameter : jtypeParameters) {
+ addTypeParameter(jtypeParameter);
+ }
+ }
}
- /**
- * @param enclosingType
- * @param ctor
- */
JAbstractMethod(JAbstractMethod srcMethod) {
this.annotations = new Annotations(srcMethod.annotations);
this.bodyEnd = srcMethod.bodyEnd;
@@ -255,10 +258,6 @@
params.add(param);
}
- void addTypeParameter(JTypeParameter typeParameter) {
- typeParams.add(typeParameter);
- }
-
boolean hasParamTypes(JType[] paramTypes) {
if (params.size() != paramTypes.length) {
return false;
@@ -274,4 +273,8 @@
}
return true;
}
+
+ private void addTypeParameter(JTypeParameter typeParameter) {
+ typeParams.add(typeParameter);
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java
index 4ba1607..4b74e4f 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -33,7 +33,7 @@
Object defaultValue,
Map<Class<? extends Annotation>, Annotation> declaredAnnotations) {
super(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd,
- declaredAnnotations);
+ declaredAnnotations, null);
this.defaultValue = defaultValue;
}
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 504eaa3..a52b4e1 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
@@ -26,13 +26,16 @@
public JConstructor(JClassType enclosingType, String name, int declStart,
int declEnd, int bodyStart, int bodyEnd) {
- this(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd, null);
+ this(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd, null, null);
}
public JConstructor(JClassType enclosingType, String name, int declStart,
int declEnd, int bodyStart, int bodyEnd,
- Map<Class<? extends Annotation>, Annotation> declaredAnnotations) {
- super(name, declStart, declEnd, bodyStart, bodyEnd, declaredAnnotations);
+ Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
+ JTypeParameter[] jtypeParameters) {
+ super(name, declStart, declEnd, bodyStart, bodyEnd, declaredAnnotations,
+ jtypeParameters);
+
this.enclosingType = enclosingType;
enclosingType.addConstructor(this);
}
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 02f60a5..50441dc 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -52,9 +52,15 @@
public JGenericType(TypeOracle oracle, CompilationUnitProvider cup,
JPackage declaringPackage, JClassType enclosingType, boolean isLocalType,
String name, int declStart, int declEnd, int bodyStart, int bodyEnd,
- boolean isInterface) {
+ boolean isInterface, JTypeParameter[] jtypeParameters) {
super(oracle, cup, declaringPackage, enclosingType, isLocalType, name,
declStart, declEnd, bodyStart, bodyEnd, isInterface);
+
+ if (jtypeParameters != null) {
+ for (JTypeParameter jtypeParameter : jtypeParameters) {
+ addTypeParameter(jtypeParameter);
+ }
+ }
}
@Override
@@ -128,7 +134,7 @@
return "class " + getParameterizedQualifiedSourceName();
}
- void addTypeParameter(JTypeParameter typeParameter) {
+ private void addTypeParameter(JTypeParameter typeParameter) {
typeParams.add(typeParameter);
}
}
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 bef2f11..3cf2040 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
@@ -29,13 +29,15 @@
public JMethod(JClassType enclosingType, String name, int declStart,
int declEnd, int bodyStart, int bodyEnd) {
- this(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd, null);
+ this(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd, null, null);
}
public JMethod(JClassType enclosingType, String name, int declStart,
int declEnd, int bodyStart, int bodyEnd,
- Map<Class<? extends Annotation>, Annotation> declaredAnnotations) {
- super(name, declStart, declEnd, bodyStart, bodyEnd, declaredAnnotations);
+ Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
+ JTypeParameter[] jtypeParameters) {
+ super(name, declStart, declEnd, bodyStart, bodyEnd, declaredAnnotations,
+ jtypeParameters);
this.enclosingType = enclosingType;
enclosingType.addMethod(this);
}
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 2256e6c..4262c0e 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -23,27 +23,12 @@
*/
public class JTypeParameter extends JDelegatingClassType implements HasBounds {
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,
- int ordinal) {
+ public JTypeParameter(String typeName, int ordinal) {
this.typeName = typeName;
- this.declaringMethod = declaringMethod;
- this.declaringClass = null;
this.ordinal = ordinal;
- declaringMethod.addTypeParameter(this);
- }
-
- public JTypeParameter(String typeName, JGenericType declaringClass,
- int ordinal) {
- this.typeName = typeName;
- this.declaringClass = declaringClass;
- this.declaringMethod = null;
- this.ordinal = ordinal;
- declaringClass.addTypeParameter(this);
}
@Override
@@ -60,8 +45,10 @@
return bounds;
}
- public JRealClassType getDeclaringClass() {
- return declaringClass;
+ @Override
+ public JClassType getEnclosingType() {
+ // Type parameters do not have an enclosing type.
+ return null;
}
@Override
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 1b84613..a51184e 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
@@ -19,6 +19,7 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.HasMetaData;
+import com.google.gwt.core.ext.typeinfo.HasTypeParameters;
import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
import com.google.gwt.core.ext.typeinfo.JAnnotationMethod;
import com.google.gwt.core.ext.typeinfo.JAnnotationType;
@@ -734,39 +735,88 @@
return null;
}
- private JUpperBound createTypeVariableBounds(TreeLogger logger,
+ private JUpperBound createTypeParameterBounds(TreeLogger logger,
TypeVariableBinding tvBinding) {
- TypeBinding jfirstBound = tvBinding.firstBound;
- if (jfirstBound == null) {
- // No bounds were specified, so we default to Object
- JClassType upperBound = (JClassType) resolveType(logger,
+ TypeBinding firstBound = tvBinding.firstBound;
+ if (firstBound == null) {
+ // No bounds were specified, so we default to Object. We assume that the
+ // superclass field of a TypeVariableBinding object is a Binding
+ // for a java.lang.Object, and we use this binding to find the
+ // JClassType for java.lang.Object. To be sure that our assumption
+ // about the superclass field is valid, we perform a runtime check
+ // against the name of the resolved type.
+
+ // You may wonder why we have to go this roundabout way to find a
+ // JClassType for java.lang.Object. The reason is that the TypeOracle
+ // has not been constructed as yet, so we cannot simply call
+ // TypeOracle.getJavaLangObject().
+ JClassType jupperBound = (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);
+
+ if (Object.class.getName().equals(jupperBound.getQualifiedSourceName())) {
+ return new JUpperBound(jupperBound);
+ } else {
+ return null;
+ }
}
List<JClassType> bounds = new ArrayList<JClassType>();
- JClassType firstBound = (JClassType) resolveType(logger, jfirstBound);
- if (firstBound.isClass() != null) {
- bounds.add(firstBound);
+ JClassType jfirstBound = (JClassType) resolveType(logger, firstBound);
+
+ if (jfirstBound == null) {
+ return null;
+ }
+
+ if (jfirstBound.isClass() != null) {
+ bounds.add(jfirstBound);
}
- ReferenceBinding[] jsuperInterfaces = tvBinding.superInterfaces();
- for (ReferenceBinding jsuperInterface : jsuperInterfaces) {
- JClassType superInterface = (JClassType) resolveType(logger,
- jsuperInterface);
- assert (superInterface != null);
- assert (superInterface.isInterface() != null);
- bounds.add(superInterface);
+ ReferenceBinding[] superInterfaces = tvBinding.superInterfaces();
+ for (ReferenceBinding superInterface : superInterfaces) {
+ JClassType jsuperInterface = (JClassType) resolveType(logger,
+ superInterface);
+
+ if (jsuperInterface == null || jsuperInterface.isInterface() == null) {
+ return null;
+ }
+ bounds.add(jsuperInterface);
}
return new JUpperBound(bounds.toArray(NO_JCLASSES));
}
+ /**
+ * Declares TypeParameters declared on a JGenericType or a JAbstractMethod
+ * by mapping the TypeParameters into JTypeParameters.
+ * <p/>
+ * This mapping has to be done on the first pass through the AST in order
+ * to handle declarations of the form:
+ * <<C exends GenericClass<T>, T extends SimpleClass>
+ * <p/>
+ * JDT already knows that GenericClass<T> is a parameterized type with a type
+ * argument of <T extends SimpleClass>. Therefore, in order to resolve
+ * GenericClass<T>, we must have knowledge of <T extends SimpleClass>.
+ * <p/>
+ * By calling this method on the first pass through the AST, a
+ * JTypeParameter for <T extends SimpleClass> will be created.
+ */
+ private JTypeParameter[] declareTypeParameters(TypeParameter[] typeParameters) {
+ if (typeParameters == null || typeParameters.length == 0) {
+ return null;
+ }
+
+ JTypeParameter[] jtypeParamArray = new JTypeParameter[typeParameters.length];
+ Mapper identityMapper = cacheManager.getIdentityMapper();
+
+ for (int i = 0; i < typeParameters.length; i++) {
+ TypeParameter typeParam = typeParameters[i];
+ jtypeParamArray[i] = new JTypeParameter(String.valueOf(typeParam.name), i);
+ identityMapper.put(typeParam.binding, jtypeParamArray[i]);
+ }
+
+ return jtypeParamArray;
+ }
+
private Object evaluateConstantExpression(TreeLogger logger,
Expression expression) {
if (expression instanceof MagicLiteral) {
@@ -923,9 +973,12 @@
}
/**
- * Maps a TypeDeclaration into a JClassType.
+ * Maps a TypeDeclaration into a JClassType. If the TypeDeclaration has
+ * TypeParameters (i.e, it is a generic type or method), then the
+ * TypeParameters are mapped into JTypeParameters by
+ * {@link TypeOracleBuilder#declareTypeParameters(org.eclipse.jdt.internal.compiler.ast.TypeParameter[])}
*/
- private void processType(TypeDeclaration typeDecl, JClassType enclosingType,
+ private void processType(TypeDeclaration typeDecl, JClassType jenclosingType,
boolean isLocalType) {
TypeOracle oracle = cacheManager.getTypeOracle();
@@ -942,11 +995,11 @@
}
String qname = getQualifiedName(binding);
- String jclassName;
+ String className;
if (binding instanceof LocalTypeBinding) {
- jclassName = qname.substring(qname.lastIndexOf('.') + 1);
+ className = qname.substring(qname.lastIndexOf('.') + 1);
} else {
- jclassName = getSimpleName(typeDecl);
+ className = getSimpleName(typeDecl);
}
if (oracle.findType(qname) != null) {
@@ -964,22 +1017,29 @@
int bodyStart = typeDecl.bodyStart;
int bodyEnd = typeDecl.bodyEnd;
- JRealClassType type;
+ JRealClassType jrealClassType;
if (jclassIsAnnonation) {
- type = new JAnnotationType(oracle, cup, pkg, enclosingType, isLocalType,
- jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf);
- } else if (maybeGeneric(typeDecl, enclosingType)) {
- type = new JGenericType(oracle, cup, pkg, enclosingType, isLocalType,
- jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf);
+ jrealClassType = new JAnnotationType(oracle, cup, pkg, jenclosingType, isLocalType,
+ className, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf);
+ } else if (maybeGeneric(typeDecl, jenclosingType)) {
+ // Go through and create declarations for each of the type parameters on
+ // the generic class or method
+ JTypeParameter[] jtypeParameters =
+ declareTypeParameters(typeDecl.typeParameters);
+
+ JGenericType jgenericType = new JGenericType(oracle, cup, pkg, jenclosingType, isLocalType,
+ className, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf, jtypeParameters);
+
+ jrealClassType = jgenericType;
} else if (binding.isEnum()) {
- type = new JEnumType(oracle, cup, pkg, enclosingType, isLocalType,
- jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf);
+ jrealClassType = new JEnumType(oracle, cup, pkg, jenclosingType, isLocalType,
+ className, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf);
} else {
- type = new JRealClassType(oracle, cup, pkg, enclosingType, isLocalType,
- jclassName, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf);
+ jrealClassType = new JRealClassType(oracle, cup, pkg, jenclosingType, isLocalType,
+ className, declStart, declEnd, bodyStart, bodyEnd, jclassIsIntf);
}
- cacheManager.setTypeForBinding(binding, type);
+ cacheManager.setTypeForBinding(binding, jrealClassType);
}
private boolean resolveAnnotation(
@@ -1018,6 +1078,33 @@
return true;
}
+ private boolean resolveBoundForTypeParameter(TreeLogger logger,
+ HasTypeParameters genericElement, TypeParameter typeParameter,
+ int ordinal) {
+ JBound jbounds = createTypeParameterBounds(logger, typeParameter.binding);
+
+ if (jbounds == null) {
+ return false;
+ }
+
+ genericElement.getTypeParameters()[ordinal].setBounds(jbounds);
+
+ return true;
+ }
+
+ private boolean resolveBoundsForTypeParameters(TreeLogger logger,
+ HasTypeParameters genericElement, TypeParameter[] typeParameters) {
+ if (typeParameters != null) {
+ for (int i = 0; i < typeParameters.length; ++i) {
+ if (!resolveBoundForTypeParameter(logger,
+ genericElement, typeParameters[i], i)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
private boolean resolveField(TreeLogger logger, char[] unitSource,
JClassType enclosingType, FieldDeclaration jfield) {
@@ -1109,13 +1196,17 @@
}
JAbstractMethod method;
- 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())) {
+
+ // Declare the type parameters. We will pass them into the constructors for
+ // JConstructor/JMethod/JAnnotatedMethod. Then, we'll do a second pass to
+ // resolve the bounds on each JTypeParameter object.
+ JTypeParameter[] jtypeParameters = declareTypeParameters(jmethod.typeParameters());
+
+ if (jmethod.isConstructor()) {
+ method = new JConstructor(enclosingType, name, declStart, declEnd,
+ bodyStart, bodyEnd, declaredAnnotations, jtypeParameters);
+ // Do a second pass to resolve the bounds on each JTypeParameter.
+ if (!resolveBoundsForTypeParameters(logger, method, jmethod.typeParameters())) {
return false;
}
} else {
@@ -1130,12 +1221,13 @@
bodyStart, bodyEnd, defaultValue, declaredAnnotations);
} else {
method = new JMethod(enclosingType, name, declStart, declEnd,
- bodyStart, bodyEnd, declaredAnnotations);
+ bodyStart, bodyEnd, declaredAnnotations, jtypeParameters);
}
- // Resolve the type parameters, since they may be used as the return type,
- // etc.
- if (!resolveTypeParameters(logger, method, jmethod.typeParameters())) {
+ // Do a second pass to resolve the bounds on each JTypeParameter.
+ // The type parameters must be resolved at this point, because they may
+ // be used in the resolution of the method's return type.
+ if (!resolveBoundsForTypeParameters(logger, method, jmethod.typeParameters())) {
return false;
}
@@ -1488,8 +1580,8 @@
}
private boolean resolveTypeDeclaration(TreeLogger logger, char[] unitSource,
- TypeDeclaration jclass) {
- SourceTypeBinding binding = jclass.binding;
+ TypeDeclaration clazz) {
+ SourceTypeBinding binding = clazz.binding;
if (binding.constantPoolName() == null) {
/*
* Weird case: if JDT determines that this local class is totally
@@ -1503,12 +1595,12 @@
// Handle package-info classes.
if (isPackageInfoTypeName(qname)) {
- return resolvePackage(logger, jclass);
+ return resolvePackage(logger, clazz);
}
// Just resolve the type.
- JRealClassType type = (JRealClassType) resolveType(logger, binding);
- if (type == null) {
+ JRealClassType jtype = (JRealClassType) resolveType(logger, binding);
+ if (jtype == null) {
// Failed to resolve.
//
return false;
@@ -1516,36 +1608,38 @@
// Add modifiers.
//
- type.addModifierBits(Shared.bindingToModifierBits(jclass.binding));
+ jtype.addModifierBits(Shared.bindingToModifierBits(clazz.binding));
// Resolve annotations
Map<Class<? extends java.lang.annotation.Annotation>, java.lang.annotation.Annotation> declaredAnnotations = newAnnotationMap();
- if (!resolveAnnotations(logger, jclass.annotations, declaredAnnotations)) {
+ if (!resolveAnnotations(logger, clazz.annotations, declaredAnnotations)) {
// Failed to resolve.
//
return false;
}
- type.addAnnotations(declaredAnnotations);
+ jtype.addAnnotations(declaredAnnotations);
- // Resolve type parameters for generic types
- JGenericType genericType = type.isGenericType();
- if (genericType != null
- && !resolveTypeParameters(logger, type.isGenericType(),
- jclass.typeParameters)) {
+ // Resolve bounds for type parameters on generic types. Note that this
+ // step does not apply to type parameters on generic methods; that
+ // occurs during the method resolution stage.
+ JGenericType jGenericType = jtype.isGenericType();
+ if (jGenericType != null
+ && !resolveBoundsForTypeParameters(logger, jtype.isGenericType(),
+ clazz.typeParameters)) {
// Failed to resolve
return false;
}
// Resolve superclass (for classes only).
//
- if (type.isInterface() == null) {
+ if (jtype.isInterface() == null) {
ReferenceBinding superclassRef = binding.superclass;
if (superclassRef != null) {
- JClassType superclass = (JClassType) resolveType(logger, superclassRef);
- if (superclass == null) {
+ JClassType jsuperClass = (JClassType) resolveType(logger, superclassRef);
+ if (jsuperClass == null) {
return false;
}
- type.setSuperclass(superclass);
+ jtype.setSuperclass(jsuperClass);
}
}
@@ -1554,88 +1648,46 @@
ReferenceBinding[] superintfRefs = binding.superInterfaces;
for (int i = 0; i < superintfRefs.length; i++) {
ReferenceBinding superintfRef = superintfRefs[i];
- JClassType intf = (JClassType) resolveType(logger, superintfRef);
- if (intf == null) {
+ JClassType jinterface = (JClassType) resolveType(logger, superintfRef);
+ if (jinterface == null) {
// Failed to resolve.
//
return false;
}
- type.addImplementedInterface(intf);
+ jtype.addImplementedInterface(jinterface);
}
// Resolve fields.
//
- FieldDeclaration[] jfields = jclass.fields;
- if (!resolveFields(logger, unitSource, type, jfields)) {
+ FieldDeclaration[] fields = clazz.fields;
+ if (!resolveFields(logger, unitSource, jtype, fields)) {
return false;
}
- // Resolve methods.
- //
- AbstractMethodDeclaration[] jmethods = jclass.methods;
- if (!resolveMethods(logger, unitSource, type, jmethods)) {
+ // Resolve methods. This also involves the declaration of type
+ // variables on generic methods, and the resolution of the bounds
+ // on these type variables.
+
+ // One would think that it would be better to perform the declaration
+ // of type variables on methods at the time when we are processing
+ // all of the classes. Unfortunately, when we are processing classes,
+ // we do not have enough information about their methods to analyze
+ // their type variables. Hence, the type variable declaration and
+ // bounds resolution for generic methods must happen after the resolution
+ // of methods is complete.
+ AbstractMethodDeclaration[] methods = clazz.methods;
+ if (!resolveMethods(logger, unitSource, jtype, methods)) {
return false;
}
// Get tags.
//
- if (jclass.javadoc != null) {
- if (!parseMetaDataTags(unitSource, type, jclass.javadoc)) {
+ if (clazz.javadoc != null) {
+ if (!parseMetaDataTags(unitSource, jtype, clazz.javadoc)) {
return false;
}
}
return true;
}
-
- private boolean resolveTypeParameter(TreeLogger logger,
- 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,
- JAbstractMethod method, TypeParameter[] jtypeParameters) {
- if (jtypeParameters != null) {
- for (int i = 0; i < jtypeParameters.length; ++i) {
- 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;
- }
- }
- }
- return true;
- }
}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JAbstractMethodTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JAbstractMethodTest.java
new file mode 100644
index 0000000..25c5139
--- /dev/null
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JAbstractMethodTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.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.GenericClassWithDependentTypeBounds;
+import com.google.gwt.core.ext.typeinfo.test.GenericClassWithTypeBound;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+
+/**
+ * Tests for {@link JAbstractMethod}.
+ */
+public class JAbstractMethodTest 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 JAbstractMethodTest() throws UnableToCompleteException {
+ }
+
+ /**
+ * Test method for {@link
+ * com.google.gwt.core.ext.typeinfo.JAbstractMethod#getTypeParameters()}. This
+ * test is similar in nature to
+ * {@link com.google.gwt.core.ext.typeinfo.JGenericTypeTest#testGetDependentTypeParameters()},
+ * except that it is verifying the type parameters on a method declaration,
+ * as opposed to a class declaration.
+ *
+ * NOTE: The test types used are:
+ * {@link GenericClassWithDependentTypeBounds}
+ * {@link GenericClassWithTypeBound}
+ *
+ * @throws NotFoundException
+ */
+ public void testGenericMethodWithDependentTypeParameters()
+ throws NotFoundException {
+
+ TypeOracle oracle = moduleContext.getOracle();
+
+ // Get the type.
+
+ JClassType type = oracle.getType(
+ GenericClassWithDependentTypeBounds.class.getName());
+
+ // Get its methods (not constructors). There should be only one method.
+
+ JMethod [] methods = type.getMethods();
+ assertEquals(1, methods.length);
+
+ // Make sure this method is a generic method by checking its type
+ // parameters. The method should have two type parameters.
+
+ JMethod method = methods[0];
+ JTypeParameter [] typeParameters = method.getTypeParameters();
+ assertEquals(2, typeParameters.length);
+
+ // Examine the first type parameter. Its name should be 'Q'.
+
+ JTypeParameter typeParameter = typeParameters[0];
+ assertEquals("Q", typeParameter.getName());
+
+ // Check the bound of the first type parameter. It should be a single
+ // upper bound.
+
+ JBound genericTypeBound = typeParameter.getBounds();
+ assertNotNull(genericTypeBound.isUpperBound());
+ JClassType [] genericTypeBounds = genericTypeBound.getBounds();
+ assertEquals(1, genericTypeBounds.length);
+
+ // Check to see that the upper bound is a parameterized type.
+
+ JClassType upperBoundType = genericTypeBounds[0];
+ JParameterizedType upperBoundParameterizedType =
+ upperBoundType.isParameterized();
+ assertNotNull(upperBoundParameterizedType);
+
+ // Examine the parameterized type. Its name should be
+ // 'GenericClassWithTypeBound'. The base type of the parameterized type
+ // should be a reference to the class 'GenericClassWithTypeBound'.
+
+ assertEquals("GenericClassWithTypeBound", upperBoundParameterizedType.getName());
+ assertEquals(upperBoundParameterizedType.getBaseType(),
+ oracle.getType(GenericClassWithTypeBound.class.getName()));
+
+ // Check the type arguments for the parameterized type. There should be a
+ // single type argument.
+
+ JClassType [] typeArgs = upperBoundParameterizedType.getTypeArgs();
+ assertEquals(1, typeArgs.length);
+
+ // Examine the first type argument. It should be a type parameter.
+
+ JClassType typeArg = typeArgs[0];
+ JTypeParameter typeArgTypeParameter = typeArg.isTypeParameter();
+ assertNotNull(typeArgTypeParameter);
+
+ // Check the name of the type parameter. It should be 'P'.
+
+ assertEquals("P", typeArgTypeParameter.getName());
+
+ // Check the bound of the type parameter. It should have a single upper
+ // bound.
+
+ JBound typeArgBound = typeArgTypeParameter.getBounds();
+ assertNotNull(typeArgBound.isUpperBound());
+ JClassType [] typeArgBounds = typeArgBound.getBounds();
+ assertEquals(1, typeArgBounds.length);
+
+ // Verify that the bound type is actually a reference to java.io.Serializable.
+
+ JClassType typeArgUpperBoundType = typeArgBounds[0];
+ assertEquals(typeArgUpperBoundType, oracle.getType(Serializable.class.getName()));
+
+ // Now look at the second type parameter on the generic method. It should
+ // be identical to the type argument of the the first type parameter
+ // (remember, the first type parameter was a paramaterized type).
+
+ JTypeParameter secondTypeParameter = typeParameters[1];
+ assertEquals(secondTypeParameter, typeArgTypeParameter);
+ }
+}
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
index 373444c..5a443f1 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JGenericTypeTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -18,10 +18,14 @@
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.GenericClassWithDependentTypeBounds;
+import com.google.gwt.core.ext.typeinfo.test.GenericClassWithTypeBound;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
+import java.io.Serializable;
+
/**
* Tests for {@link JGenericType}.
*/
@@ -35,6 +39,103 @@
}
/**
+ * Test method for {@link
+ * com.google.gwt.core.ext.typeinfo.JGenericType#getTypeParameters()}. This
+ * test goes beyond
+ * {@link com.google.gwt.core.ext.typeinfo.JGenericTypeTest#testGetTypeParameters()}
+ * by testing generic types that have type parameters which are dependent on
+ * one another.
+ *
+ * NOTE: This test does not make use of the
+ * {@link com.google.gwt.core.ext.typeinfo.JGenericTypeTest#getTestType()}
+ * method. The test types used are:
+ * {@link GenericClassWithDependentTypeBounds}
+ * {@link GenericClassWithTypeBound}
+ *
+ * @throws NotFoundException
+ */
+ public void testGetDependentTypeParameters() throws NotFoundException {
+
+ TypeOracle oracle = moduleContext.getOracle();
+
+ // Get the generic type
+
+ JClassType type = oracle.getType(
+ GenericClassWithDependentTypeBounds.class.getName());
+ JGenericType genericType = type.isGenericType();
+ assertNotNull(genericType);
+
+ // Get its type parameters
+
+ JTypeParameter [] typeParameters = genericType.getTypeParameters();
+ assertEquals(2, typeParameters.length);
+
+ // Examine the first type parameter. Its name should be 'C'.
+
+ JTypeParameter typeParameter = typeParameters[0];
+ assertEquals("C", typeParameter.getName());
+
+ // Check the bound of the first type parameter. It should be a single
+ // upper bound.
+
+ JBound genericTypeBound = typeParameter.getBounds();
+ assertNotNull(genericTypeBound.isUpperBound());
+ JClassType [] genericTypeBounds = genericTypeBound.getBounds();
+ assertEquals(1, genericTypeBounds.length);
+
+ // Check to see that the upper bound is a parameterized type.
+
+ JClassType upperBoundType = genericTypeBounds[0];
+ JParameterizedType upperBoundParameterizedType =
+ upperBoundType.isParameterized();
+ assertNotNull(upperBoundParameterizedType);
+
+ // Examine the parameterized type. Its name should be
+ // 'GenericClassWithTypeBound'. The base type of the parameterized type
+ // should be a reference to the class 'GenericClassWithTypeBound'.
+
+ assertEquals("GenericClassWithTypeBound", upperBoundParameterizedType.getName());
+ assertEquals(upperBoundParameterizedType.getBaseType(),
+ oracle.getType(GenericClassWithTypeBound.class.getName()));
+
+ // Check the type arguments for the parameterized type. There should be a
+ // single type argument.
+
+ JClassType [] typeArgs = upperBoundParameterizedType.getTypeArgs();
+ assertEquals(1, typeArgs.length);
+
+ // Examine the first type argument. It should be a type parameter.
+
+ JClassType typeArg = typeArgs[0];
+ JTypeParameter typeArgTypeParameter = typeArg.isTypeParameter();
+ assertNotNull(typeArgTypeParameter);
+
+ // Check the name of the type parameter. It should be 'M'.
+
+ assertEquals("M", typeArgTypeParameter.getName());
+
+ // Check the bound of the type parameter. It should have a single upper
+ // bound.
+
+ JBound typeArgBound = typeArgTypeParameter.getBounds();
+ assertNotNull(typeArgBound.isUpperBound());
+ JClassType [] typeArgBounds = typeArgBound.getBounds();
+ assertEquals(1, typeArgBounds.length);
+
+ // Verify that the bound type is actually a reference to java.io.Serializable.
+
+ JClassType typeArgUpperBoundType = typeArgBounds[0];
+ assertEquals(typeArgUpperBoundType, oracle.getType(Serializable.class.getName()));
+
+ // Now look at the second type parameter on the generic type. It should
+ // be identical to the type argument of the the first type parameter
+ // (remember, the first type parameter was a paramaterized type).
+
+ JTypeParameter secondTypeParameter = typeParameters[1];
+ assertEquals(secondTypeParameter, typeArgTypeParameter);
+ }
+
+ /**
* Test method for
* {@link com.google.gwt.core.ext.typeinfo.JGenericType#getErasedType()}.
*
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
index 28aa3d8..9066707 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JTypeParameterTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -22,12 +22,7 @@
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
/**
* Tests for {@link JTypeParameter}.
@@ -56,9 +51,7 @@
@Override
public void testGetEnclosingType() throws NotFoundException {
JTypeParameter testType = getTestType();
- assertEquals(
- moduleContext.getOracle().getType(GenericClass.class.getName()),
- testType.getDeclaringClass());
+ assertNull(testType.getEnclosingType());
}
@Override
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
index 8d2db69..54dadb2 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleSuite.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleSuite.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -23,6 +23,7 @@
TestSuite suite = new TestSuite("Test suite for TypeOracle");
suite.addTestSuite(AnnotationsTest.class);
suite.addTestSuite(JArrayTypeTest.class);
+ suite.addTestSuite(JAbstractMethodTest.class);
suite.addTestSuite(JClassTypeTest.class);
suite.addTestSuite(JEnumTypeTest.class);
suite.addTestSuite(JGenericTypeTest.class);
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClassWithDependentTypeBounds.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClassWithDependentTypeBounds.java
new file mode 100644
index 0000000..6930c6f
--- /dev/null
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClassWithDependentTypeBounds.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo.test;
+
+import java.io.Serializable;
+
+/**
+ * Tests a generic class that has type parameters that depend on each other.
+ * Also tests a generic method with type parameters that depend on each other.
+ *
+ * @param <C>
+ * @param <M>
+ */
+public class GenericClassWithDependentTypeBounds
+ <C extends GenericClassWithTypeBound<M>, M extends Serializable> {
+
+ public <Q extends GenericClassWithTypeBound<P>, P extends Serializable> void genericMethod(Q param) {
+ }
+}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClassWithTypeBound.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClassWithTypeBound.java
new file mode 100644
index 0000000..058807d
--- /dev/null
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/GenericClassWithTypeBound.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.ext.typeinfo.test;
+
+import java.io.Serializable;
+
+/**
+ * Auxillary test class used by
+ * {@link GenericClassWithDependentTypeBounds}.
+ *
+ * @param <M>
+ */
+public class GenericClassWithTypeBound<M extends Serializable> {
+}