| /* |
| * 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); |
| } |