blob: 990648eb66de95709a036c63a125810cba251441 [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.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.dev.util.collect.HashSet;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Type used to represent any non-primitive type.
*/
public abstract class JClassType implements
com.google.gwt.core.ext.typeinfo.JClassType {
/**
* Returns all of the superclasses and superinterfaces for a given type
* including the type itself. The returned set maintains an internal
* breadth-first ordering of the type, followed by its interfaces (and their
* super-interfaces), then the supertype and its interfaces, and so on.
*/
protected static Set<JClassType> getFlattenedSuperTypeHierarchy(
JClassType type) {
Set<JClassType> flattened = type.flattenedSupertypes;
if (flattened == null) {
flattened = new LinkedHashSet<JClassType>();
getFlattenedSuperTypeHierarchyRecursive(type, flattened);
// flattened.size() > 1 for all types other than Object
type.flattenedSupertypes = Collections.unmodifiableSet(flattened);
}
return flattened;
}
private static void getFlattenedSuperTypeHierarchyRecursive(JClassType type,
Set<JClassType> typesSeen) {
if (typesSeen.contains(type)) {
return;
}
typesSeen.add(type);
// Check the interfaces
JClassType[] intfs = type.getImplementedInterfaces();
for (JClassType intf : intfs) {
typesSeen.addAll(getFlattenedSuperTypeHierarchy(intf));
}
// Superclass
JClassType superclass = type.getSuperclass();
if (superclass != null) {
typesSeen.addAll(getFlattenedSuperTypeHierarchy(superclass));
}
}
/**
* Cached set of supertypes for this type (including itself). If null, the set
* has not been calculated yet.
*/
private Set<JClassType> flattenedSupertypes;
/**
* True if this type may be enhanced with server-only fields. This property is
* 'sticky' and may be set but not unset, since we need to generate the
* relevant RPC code for handling the server fields if there is any chance the
* class will be enhanced.
*/
private boolean isEnhanced = false;
@Override
public JParameterizedType asParameterizationOf(
com.google.gwt.core.ext.typeinfo.JGenericType type) {
Set<JClassType> supertypes = getFlattenedSuperTypeHierarchy(this);
for (JClassType supertype : supertypes) {
JParameterizedType isParameterized = supertype.isParameterized();
if (isParameterized != null && isParameterized.getBaseType() == type) {
return isParameterized;
}
JRawType isRaw = supertype.isRawType();
if (isRaw != null && isRaw.getBaseType() == type) {
return isRaw.asParameterizedByWildcards();
}
}
return null;
}
/**
* All types use identity for comparison.
*/
@Override
public final boolean equals(Object obj) {
return super.equals(obj);
}
/**
* Find an annotation on a type or on one of its superclasses or
* superinterfaces.
* <p>
* This provides semantics similar to that of
* {@link java.lang.annotation.Inherited} except that it checks all types to
* which this type is assignable. {@code @Inherited} only works on
* superclasses, not superinterfaces.
* <p>
* Annotations present on the superclass chain will be returned preferentially
* over those found in the superinterface hierarchy. Note that the annotation
* does not need to be tagged with {@code @Inherited} in order to be returned
* from the superclass chain.
*
* @param annotationType the type of the annotation to look for
* @return the desired annotation or <code>null</code> if the annotation is
* not present in the type's type hierarchy
*/
@Override
public <T extends Annotation> T findAnnotationInTypeHierarchy(
Class<T> annotationType) {
// Remember what we've seen to avoid loops
Set<JClassType> seen = new HashSet<JClassType>();
// Work queue
List<JClassType> searchTypes = new LinkedList<JClassType>();
searchTypes.add(this);
T toReturn = null;
while (!searchTypes.isEmpty()) {
JClassType current = searchTypes.remove(0);
if (!seen.add(current)) {
continue;
}
toReturn = current.getAnnotation(annotationType);
if (toReturn != null) {
/*
* First one wins. It might be desirable at some point to have a
* variation that can return more than one instance of the annotation if
* it is present on multiple supertypes.
*/
break;
}
if (current.getSuperclass() != null) {
// Add the superclass at the front of the list
searchTypes.add(0, current.getSuperclass());
}
// Superinterfaces
Collections.addAll(searchTypes, current.getImplementedInterfaces());
}
return toReturn;
}
@Override
public abstract JConstructor findConstructor(JType[] paramTypes);
@Override
public abstract JField findField(String name);
@Override
public abstract JMethod findMethod(String name, JType[] paramTypes);
@Override
public abstract JClassType findNestedType(String typeName);
@Override
public abstract <T extends Annotation> T getAnnotation(
Class<T> annotationClass);
@Override
public abstract Annotation[] getAnnotations();
@Override
public abstract JConstructor getConstructor(JType[] paramTypes)
throws NotFoundException;
@Override
public abstract JConstructor[] getConstructors();
@Override
public abstract Annotation[] getDeclaredAnnotations();
@Override
public abstract JClassType getEnclosingType();
@Override
public abstract JClassType getErasedType();
@Override
public abstract JField getField(String name);
@Override
public abstract JField[] getFields();
/**
* Returns all of the superclasses and superinterfaces for a given type
* including the type itself. The returned set maintains an internal
* breadth-first ordering of the type, followed by its interfaces (and their
* super-interfaces), then the supertype and its interfaces, and so on.
*/
@Override
public Set<JClassType> getFlattenedSupertypeHierarchy() {
// Retuns an immutable set
return getFlattenedSuperTypeHierarchy(this);
}
@Override
public abstract JClassType[] getImplementedInterfaces();
/**
* Iterates over the most-derived declaration of each unique inheritable
* method available in the type hierarchy of the specified type, including
* those found in superclasses and superinterfaces. A method is inheritable if
* its accessibility is <code>public</code>, <code>protected</code>, or
* package protected.
*
* This method offers a convenient way for Generators to find candidate
* methods to call from a subclass.
*
* @return an array of {@link JMethod} objects representing inheritable
* methods
*/
@Override
public abstract JMethod[] getInheritableMethods();
@Override
public abstract String getJNISignature();
@Override
public JType getLeafType() {
return this;
}
@Override
public abstract JMethod getMethod(String name, JType[] paramTypes)
throws NotFoundException;
/*
* Returns the declared methods of this class (not any superclasses or
* superinterfaces).
*/
@Override
public abstract JMethod[] getMethods();
@Override
public abstract String getName();
@Override
public abstract JClassType getNestedType(String typeName)
throws NotFoundException;
@Override
public abstract JClassType[] getNestedTypes();
@Override
public abstract TypeOracle getOracle();
@Override
public abstract JMethod[] getOverloads(String name);
/**
* Iterates over the most-derived declaration of each unique overridable
* method available in the type hierarchy of the specified type, including
* those found in superclasses and superinterfaces. A method is overridable if
* it is not <code>final</code> and its accessibility is <code>public</code>,
* <code>protected</code>, or package protected.
*
* Deferred binding generators often need to generate method implementations;
* this method offers a convenient way to find candidate methods to implement.
*
* Note that the behavior does not match
* {@link Class#getMethod(String, Class[])}, which does not return the most
* derived method in some cases.
*
* @return an array of {@link JMethod} objects representing overridable
* methods
*/
@Override
public abstract JMethod[] getOverridableMethods();
@Override
public abstract JPackage getPackage();
@Override
public String getParameterizedQualifiedSourceName() {
return getQualifiedSourceName();
}
/**
* TODO(scottb): remove if we can resolve param names differently.
*/
@Override
public abstract String getQualifiedBinaryName();
@Override
public abstract String getQualifiedSourceName();
@Override
public abstract String getSimpleSourceName();
/**
* Returns all subtypes for this type. This means various things:
* <ol>
* <li>Array: subtypes are those array types with the same number of dimensions as this type,
* and whose base element type is a subtype of this type's element type.</li>
* <li>Wildcards: if ? extends X, subtypes are subtypes of X. If ? super X: no subtypes.
* <li>Named type parameter: subtypes are (1) those subtypes of the "base" type that are
* assignable to this, plus (2) the first bound of the parameter, if the bound is both
* assignable to this and not an interface. The "base" is the type itself, except for
* delegating types, where the base is the result of <code>getBaseType()</code>.</li>
* <li>Real class: subtypes are those real classes that are subtypes of this class in the
* class hierarchy. Interfaces aren't subtypes of {@code Object}.</li>
* <li>Parameterized type: subtypes are those subtypes of the generic type of this type which
* can be parameterized with the right types so that they have this type as a supertype.
* The subtypes are parameterized as described, with minimal parameterization.</li>
* <li>Raw type: subtypes are the subtypes of the generic type of this type, as raw types if
* they themselves are generic.</li>
* </ol>
*/
@Override
public abstract JClassType[] getSubtypes();
@Override
public abstract JClassType getSuperclass();
/**
* All types use identity for comparison.
*/
@Override
public final int hashCode() {
return super.hashCode();
}
@Override
public abstract boolean isAbstract();
/**
* Returns this instance if it is a annotation or <code>null</code> if it is
* not.
*
* @return this instance if it is a annotation or <code>null</code> if it is
* not
*/
@Override
public JAnnotationType isAnnotation() {
return null;
}
@Override
public abstract boolean isAnnotationPresent(
Class<? extends Annotation> annotationClass);
@Override
public abstract JArrayType isArray();
/**
* Returns <code>true</code> if this {@link JClassType} is assignable from the
* specified {@link JClassType} parameter.
*
* @param possibleSubtype possible subtype of this {@link JClassType}
* @return <code>true</code> if this {@link JClassType} is assignable from the
* specified {@link JClassType} parameter
*
* @throws NullPointerException if <code>possibleSubtype</code> is
* <code>null</code>
*/
@Override
public boolean isAssignableFrom(
com.google.gwt.core.ext.typeinfo.JClassType possibleSubtype) {
if (possibleSubtype == null) {
throw new NullPointerException("possibleSubtype");
}
return new AssignabilityChecker().isAssignable((JClassType) possibleSubtype, this);
}
/**
* Returns <code>true</code> if this {@link JClassType} is assignable to the
* specified {@link JClassType} parameter.
*
* @param possibleSupertype possible supertype of this {@link JClassType}
* @return <code>true</code> if this {@link JClassType} is assignable to the
* specified {@link JClassType} parameter
*
* @throws NullPointerException if <code>possibleSupertype</code> is
* <code>null</code>
*/
@Override
public boolean isAssignableTo(
com.google.gwt.core.ext.typeinfo.JClassType possibleSupertype) {
if (possibleSupertype == null) {
throw new NullPointerException("possibleSupertype");
}
return new AssignabilityChecker().isAssignable(this, (JClassType) possibleSupertype);
}
@Override
public abstract JClassType isClass();
@Override
public JClassType isClassOrInterface() {
JClassType type = isClass();
if (type != null) {
return type;
}
return isInterface();
}
/**
* Determines if the class can be constructed using a simple <code>new</code>
* operation. Specifically, the class must
* <ul>
* <li>be a class rather than an interface,</li>
* <li>have either no constructors or a parameterless constructor, and</li>
* <li>be a top-level class or a static nested class.</li>
* </ul>
*
* @return <code>true</code> if the type is default instantiable, or
* <code>false</code> otherwise
*/
@Override
public abstract boolean isDefaultInstantiable();
/**
* Returns true if the type may be enhanced on the server to contain extra
* fields that are unknown to client code.
*
* @return <code>true</code> if the type might be enhanced on the server
*/
@Override
public final boolean isEnhanced() {
return isEnhanced;
}
/**
* 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
*/
@Override
public abstract JEnumType isEnum();
@Override
public abstract boolean isFinal();
@Override
public abstract JGenericType isGenericType();
@Override
public abstract JClassType isInterface();
/**
* Tests if this type is contained within another type.
*
* @return true if this type has an enclosing type, false if this type is a
* top-level type
*/
@Override
public abstract boolean isMemberType();
@Override
public abstract JParameterizedType isParameterized();
@Override
public abstract JPrimitiveType isPrimitive();
@Override
public abstract boolean isPrivate();
@Override
public abstract boolean isProtected();
@Override
public abstract boolean isPublic();
@Override
public boolean isPackageProtected() {
return !isPrivate() && !isPublic() && !isProtected();
}
// TODO: Rename this to isRaw
@Override
public abstract JRawType isRawType();
@Override
public abstract boolean isStatic();
@Override
public JTypeParameter isTypeParameter() {
return null;
}
@Override
public abstract JWildcardType isWildcard();
/**
* Indicates that the type may be enhanced on the server to contain extra
* fields that are unknown to client code.
*
* TODO(rice): find a better way to do this.
*/
@Override
public void setEnhanced() {
this.isEnhanced = true;
}
@Override
public String toString() {
return this.getQualifiedSourceName();
}
protected abstract void acceptSubtype(JClassType me);
protected abstract void getInheritableMethodsOnSuperclassesAndThisClass(
Map<String, JMethod> 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 abstract void getInheritableMethodsOnSuperinterfacesAndMaybeThisInterface(
Map<String, JMethod> methodsBySignature);
protected abstract int getModifierBits();
protected JMaybeParameterizedType isMaybeParameterizedType() {
return null;
}
/**
* Tells this type's superclasses and superinterfaces about it.
*/
protected abstract void notifySuperTypesOf(JClassType me);
protected abstract void removeSubtype(JClassType me);
abstract void addConstructor(JConstructor ctor);
abstract void addField(JField field);
abstract void addImplementedInterface(JClassType intf);
abstract void addMethod(JMethod method);
abstract void addModifierBits(int bits);
abstract void addNestedType(JClassType type);
abstract JClassType findNestedTypeImpl(String[] typeName, int index);
/**
* 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 JClassType getSubstitutedType(JParameterizedType parameterizedType);
abstract void notifySuperTypes();
/**
* Removes references to this instance from all of its super types.
*/
abstract void removeFromSupertypes();
abstract void setSuperclass(JClassType type);
}