/* * 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.StringInterner; import com.google.gwt.dev.util.collect.IdentitySets; import com.google.gwt.dev.util.collect.Lists; import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; import java.util.Set; /** * Type representing a Java class or interface type that a user would declare. */ public class JRealClassType extends JClassType implements com.google.gwt.core.ext.typeinfo.JRealClassType { private Set<JClassType> allSubtypes = IdentitySets.create(); private final Annotations annotations = new Annotations(); private final JPackage declaringPackage; /** * Set when this class is resolved, then never modified. */ private JClassType enclosingType; private List<JClassType> interfaces = Lists.create(); private final boolean isInterface; private String lazyQualifiedBinaryName; private String lazyQualifiedName; private final Members members = new Members(this); private int modifierBits; private final String name; private final String nestedName; private final TypeOracle oracle; private JClassType superclass; private long lastModifiedTime; /** * Create a class type that reflects an actual type. * * @param oracle * @param declaringPackage * @param enclosingTypeName the fully qualified source name of the enclosing * class or null if a top-level class - setEnclosingType must be * called later with the proper enclosing type if this is non-null * @param name * @param isInterface */ JRealClassType(TypeOracle oracle, JPackage declaringPackage, String enclosingTypeName, String name, boolean isInterface) { this.oracle = oracle; this.declaringPackage = declaringPackage; this.name = StringInterner.get().intern(name); this.isInterface = isInterface; if (enclosingTypeName == null) { // Add myself to my package. // declaringPackage.addType(this); // The nested name of a top-level class is its simple name. // nestedName = name; } else { // Compute my "nested name". // nestedName = enclosingTypeName + "." + name; // We will add ourselves to the enclosing class when it is set in // setEnclosingType(). } oracle.addNewType(this); } public void addLastModifiedTime(long lastModifiedTime) { this.lastModifiedTime = lastModifiedTime; } @Override public void addModifierBits(int bits) { modifierBits |= bits; } @Override public JConstructor findConstructor(JType[] paramTypes) { return members.findConstructor(paramTypes); } @Override public JField findField(String name) { return members.findField(name); } @Override public JMethod findMethod(String name, JType[] paramTypes) { return members.findMethod(name, paramTypes); } @Override public JClassType findNestedType(String typeName) { return members.findNestedType(typeName); } @Override public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { return annotations.getAnnotation(annotationClass); } @Override public Annotation[] getAnnotations() { return annotations.getAnnotations(); } @Override public JConstructor getConstructor(JType[] paramTypes) throws NotFoundException { return members.getConstructor(paramTypes); } @Override public JConstructor[] getConstructors() { return members.getConstructors(); } @Override public Annotation[] getDeclaredAnnotations() { return annotations.getDeclaredAnnotations(); } @Override public JClassType getEnclosingType() { return enclosingType; } @Override public JClassType getErasedType() { return this; } @Override public JField getField(String name) { return members.getField(name); } @Override public JField[] getFields() { return members.getFields(); } @Override public JClassType[] getImplementedInterfaces() { return interfaces.toArray(TypeOracle.NO_JCLASSES); } @Override public JMethod[] getInheritableMethods() { return members.getInheritableMethods(); } @Override public String getJNISignature() { String typeName = nestedName.replace('.', '$'); String packageName = getPackage().getName().replace('.', '/'); if (packageName.length() > 0) { packageName += "/"; } return "L" + packageName + typeName + ";"; } @Override public long getLastModifiedTime() { return lastModifiedTime; } @Override public JMethod getMethod(String name, JType[] paramTypes) throws NotFoundException { return members.getMethod(name, paramTypes); } @Override public JMethod[] getMethods() { return members.getMethods(); } @Override public String getName() { return nestedName; } @Override public JClassType getNestedType(String typeName) throws NotFoundException { return members.getNestedType(typeName); } @Override public JClassType[] getNestedTypes() { return members.getNestedTypes(); } @Override public TypeOracle getOracle() { return oracle; } @Override public JMethod[] getOverloads(String name) { return members.getOverloads(name); } @Override public JMethod[] getOverridableMethods() { return members.getOverridableMethods(); } @Override public JPackage getPackage() { return declaringPackage; } @Override public String getQualifiedBinaryName() { if (lazyQualifiedBinaryName == null) { lazyQualifiedBinaryName = ""; JPackage pkg = getPackage(); if (!pkg.isDefault()) { lazyQualifiedBinaryName = pkg.getName() + "."; } lazyQualifiedBinaryName += nestedName.replace('.', '$'); } return lazyQualifiedBinaryName; } @Override public String getQualifiedSourceName() { if (lazyQualifiedName == null) { JPackage pkg = getPackage(); if (!pkg.isDefault()) { lazyQualifiedName = pkg.getName() + "." + nestedName; } else { lazyQualifiedName = nestedName; } lazyQualifiedName = StringInterner.get().intern(lazyQualifiedName); } return lazyQualifiedName; } @Override public String getSimpleSourceName() { return name; } @Override public JClassType[] getSubtypes() { return allSubtypes.toArray(TypeOracle.NO_JCLASSES); } @Override public JClassType getSuperclass() { return superclass; } @Override public boolean isAbstract() { return 0 != (modifierBits & TypeOracle.MOD_ABSTRACT); } @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { return annotations.isAnnotationPresent(annotationClass); } @Override public JArrayType isArray() { // intentional null return null; } @Override public JClassType isClass() { return isInterface ? null : this; } /** * 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 boolean isDefaultInstantiable() { if (isInterface() != null || isAbstract()) { return false; } if (isMemberType() && !isStatic()) { return false; } if (getConstructors().length == 0) { return true; } JConstructor ctor = findConstructor(TypeOracle.NO_JTYPES); if (ctor != null) { return true; } return false; } @Override public JEnumType isEnum() { return null; } @Override public boolean isFinal() { return 0 != (getModifierBits() & TypeOracle.MOD_FINAL); } @Override public JGenericType isGenericType() { return null; } @Override public JClassType isInterface() { return isInterface ? this : null; } /** * 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 boolean isMemberType() { return enclosingType != null; } @Override public JParameterizedType isParameterized() { // intentional null return null; } @Override public JPrimitiveType isPrimitive() { // intentional null return null; } @Override public boolean isPrivate() { return 0 != (modifierBits & TypeOracle.MOD_PRIVATE); } @Override public boolean isProtected() { return 0 != (modifierBits & TypeOracle.MOD_PROTECTED); } @Override public boolean isPublic() { return 0 != (modifierBits & TypeOracle.MOD_PUBLIC); } @Override public JRawType isRawType() { // TODO Override in JGenericType? return null; } @Override public boolean isStatic() { return 0 != (modifierBits & TypeOracle.MOD_STATIC); } @Override public JWildcardType isWildcard() { return null; } @Override public String toString() { if (isInterface) { return "interface " + getQualifiedSourceName(); } else { return "class " + getQualifiedSourceName(); } } @Override protected void acceptSubtype(JClassType me) { allSubtypes = IdentitySets.add(allSubtypes, me); notifySuperTypesOf(me); } @Override protected void addConstructor(JConstructor ctor) { members.addConstructor(ctor); } @Override protected void addField(JField field) { members.addField(field); } @Override protected void addMethod(JMethod method) { members.addMethod(method); } @Override protected void addNestedType(JClassType type) { members.addNestedType(type); } @Override protected JClassType findNestedTypeImpl(String[] typeName, int index) { return members.findNestedTypeImpl(typeName, index); } @Override protected void getInheritableMethodsOnSuperclassesAndThisClass( Map<String, JMethod> methodsBySignature) { members.getInheritableMethodsOnSuperclassesAndThisClass(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 */ @Override protected void getInheritableMethodsOnSuperinterfacesAndMaybeThisInterface( Map<String, JMethod> methodsBySignature) { members.getInheritableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); } @Override protected int getModifierBits() { return modifierBits; } /** * Tells this type's superclasses and superinterfaces about it. */ @Override protected void notifySuperTypesOf(JClassType me) { // TODO(scottb): revisit if (superclass != null) { superclass.acceptSubtype(me); } for (int i = 0, n = interfaces.size(); i < n; ++i) { JClassType intf = interfaces.get(i); intf.acceptSubtype(me); } } @Override protected void removeSubtype(JClassType me) { allSubtypes = IdentitySets.remove(allSubtypes, me); if (superclass != null) { superclass.removeSubtype(me); } for (int i = 0, n = interfaces.size(); i < n; ++i) { JClassType intf = interfaces.get(i); intf.removeSubtype(me); } } void addAnnotations(Map<Class<? extends Annotation>, Annotation> declaredAnnotations) { annotations.addAnnotations(declaredAnnotations); } @Override void addImplementedInterface(JClassType intf) { assert (intf != null); interfaces = Lists.add(interfaces, intf); } @Override JRealClassType getSubstitutedType(JParameterizedType parameterizedType) { return this; } @Override void notifySuperTypes() { notifySuperTypesOf(this); } /** * Removes references to this instance from all of its super types. */ @Override void removeFromSupertypes() { removeSubtype(this); } void setEnclosingType(JClassType enclosingType) { assert this.enclosingType == null; assert enclosingType != null; this.enclosingType = enclosingType; // Add myself to my enclosing type. JRawType rawType = enclosingType.isRawType(); if (rawType != null) { enclosingType = rawType.getGenericType(); } enclosingType.addNestedType(this); } @Override void setSuperclass(JClassType type) { assert (type != null); assert (isInterface() == null); this.superclass = type; JRealClassType realSuperType; if (type.isParameterized() != null) { realSuperType = type.isParameterized().getBaseType(); } else if (type.isRawType() != null) { realSuperType = type.isRawType().getGenericType(); } else if (type instanceof JRealClassType) { realSuperType = (JRealClassType) type; } else { throw new IllegalArgumentException("Unknown type for " + type); } annotations.setParent(realSuperType.annotations); } }