blob: 07dcd5f7b69279f5e9d8e317227053bb83f49029 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.javac.typemodel;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
/**
* Represents a wildcard type argument to a parameterized type.
*/
public class JWildcardType extends JDelegatingClassType implements
com.google.gwt.core.ext.typeinfo.JWildcardType {
private final BoundType boundType;
private JClassType[] lazyLowerBounds;
private JClassType[] lazyUpperBounds;
JWildcardType(BoundType boundType, JClassType typeBound) {
this.boundType = boundType;
super.setBaseType(typeBound);
}
@Override
public JField findField(String name) {
return getBaseType().findField(name);
}
@Override
public JMethod findMethod(String name, JType[] paramTypes) {
return getBaseType().findMethod(name, paramTypes);
}
public BoundType getBoundType() {
return boundType;
}
@Override
public JClassType getErasedType() {
return getUpperBound().getErasedType();
}
@Override
public JField getField(String name) {
return getBaseType().getField(name);
}
@Override
public JField[] getFields() {
return getBaseType().getFields();
}
public JClassType getFirstBound() {
return getBaseType();
}
/**
* Returns the lower bounds of this wildcard type. If no lower bounds were
* declared, an empty array is returned.
*
* @return the lower bounds of this wildcard type
*/
public JClassType[] getLowerBounds() {
if (lazyLowerBounds == null) {
if (isUpperBound()) {
lazyLowerBounds = TypeOracle.NO_JCLASSES;
} else {
lazyLowerBounds = new JClassType[]{getFirstBound()};
}
}
return lazyLowerBounds;
}
@Override
public JMethod getMethod(String name, JType[] paramTypes)
throws NotFoundException {
return getBaseType().getMethod(name, paramTypes);
}
@Override
public JMethod[] getMethods() {
return getBaseType().getMethods();
}
@Override
public String getQualifiedBinaryName() {
// TODO(jat): !! does a binary name have meaning for a wildcard?
return toString(true);
}
@Override
public String getQualifiedSourceName() {
return toString(false);
}
@Override
public String getSimpleSourceName() {
return toString(true);
}
@Override
public JClassType[] getSubtypes() {
if (isUpperBound()) {
return getFirstBound().getSubtypes();
}
// We are not sure what the correct behavior should be for lower bound
// wildcards. ? super Number contains ? super T for all T extends Number,
// but it also includes T for Number extends T. For example, Object is a
// subtype.
return TypeOracle.NO_JCLASSES;
}
@Override
public JClassType getSuperclass() {
if (isUpperBound()) {
// The superclass of an upper bound is the upper bound.
return getFirstBound();
}
// The only safe superclass for a ? super T is Object.
return getOracle().getJavaLangObject();
}
public JClassType getUpperBound() {
if (isUpperBound()) {
return getFirstBound();
}
return getOracle().getJavaLangObject();
}
/**
* Returns the upper bounds of this wildcard type. If no upper bounds were
* declared, an array containing {@link Object} is returned.
*
* @return the upper bounds of this wildcard type
*/
public JClassType[] getUpperBounds() {
if (lazyUpperBounds == null) {
if (isUpperBound()) {
lazyUpperBounds = new JClassType[]{getFirstBound()};
} else {
// Object is the default upper bound.
lazyUpperBounds = new JClassType[]{getOracle().getJavaLangObject()};
}
}
return lazyUpperBounds;
}
@Override
public JGenericType isGenericType() {
return null;
}
@Override
public JParameterizedType isParameterized() {
return null;
}
@Override
public JRawType isRawType() {
return null;
}
@Override
public JWildcardType isWildcard() {
return this;
}
/**
* Returns <code>true</code> if this instance has the same bounds that are
* requested.
*
* @param otherWildcard
* @return <code>true</code> if this instance has the same bounds that are
* requested
*/
boolean boundsMatch(JWildcardType otherWildcard) {
return isUpperBound() == otherWildcard.isUpperBound()
&& getFirstBound() == otherWildcard.getFirstBound();
}
@Override
JClassType getSubstitutedType(JParameterizedType parameterizedType) {
return getOracle().getWildcardType(boundType,
getFirstBound().getSubstitutedType(parameterizedType));
}
private boolean isUnbound() {
return boundType == BoundType.UNBOUND;
}
private boolean isUpperBound() {
return boundType != BoundType.SUPER;
}
private String toString(boolean simpleName) {
String str = "?";
if (isUnbound()) {
return str;
} else {
str += (isUpperBound() ? " extends " : " super ");
if (simpleName) {
return str + getFirstBound().getSimpleSourceName();
} else {
return str + getFirstBound().getParameterizedQualifiedSourceName();
}
}
}
}