blob: b40ab8d9abee3e9a52003ddae52c655f8f1cae24 [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.core.ext.typeinfo;
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 {
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;
/**
* 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 isLocalType
* @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);
}
@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 JConstructor getConstructor(JType[] paramTypes)
throws NotFoundException {
return members.getConstructor(paramTypes);
}
@Override
public JConstructor[] getConstructors() {
return members.getConstructors();
}
@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 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);
}
/**
* NOTE: This method is for testing purposes only.
*/
@Override
Annotation[] getAnnotations() {
return annotations.getAnnotations();
}
/**
* NOTE: This method is for testing purposes only.
*/
@Override
Annotation[] getDeclaredAnnotations() {
return annotations.getDeclaredAnnotations();
}
@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);
}
}