package org.aspectj.weaver;
import java.io.IOException;
public class TypeVariable {
public static final TypeVariable[] NONE = new TypeVariable[0];
private String name;
private int rank;
private UnresolvedType firstbound;
private UnresolvedType superclass;
private UnresolvedType[] superInterfaces = UnresolvedType.NONE;
public static final int UNKNOWN = -1;
public static final int METHOD = 1;
public static final int TYPE = 2;
private int declaringElementKind = UNKNOWN;
private TypeVariableDeclaringElement declaringElement;
public boolean isResolved = false;
private boolean beingResolved = false;
public TypeVariable(String name) {
this.name = name;
}
public TypeVariable(String name, UnresolvedType anUpperBound) {
this(name);
this.superclass = anUpperBound;
}
public TypeVariable(String name, UnresolvedType anUpperBound, UnresolvedType[] superInterfaces) {
this(name, anUpperBound);
this.superInterfaces = superInterfaces;
}
public UnresolvedType getFirstBound() {
if (firstbound != null) {
return firstbound;
}
if (superclass == null || superclass.getSignature().equals("Ljava/lang/Object;")) {
if (superInterfaces.length > 0) {
firstbound = superInterfaces[0];
} else {
firstbound = UnresolvedType.OBJECT;
}
} else {
firstbound = superclass;
}
return firstbound;
}
public UnresolvedType getUpperBound() {
return superclass;
}
public UnresolvedType[] getSuperInterfaces() {
return superInterfaces;
}
public String getName() {
return name;
}
public TypeVariable resolve(World world) {
if (isResolved) {
return this;
}
if (beingResolved) {
return this;
}
beingResolved = true;
TypeVariable resolvedTVar = null;
if (declaringElement != null) {
if (declaringElementKind == TYPE) {
UnresolvedType declaring = (UnresolvedType) declaringElement;
ReferenceType rd = (ReferenceType) declaring.resolve(world);
TypeVariable[] tVars = rd.getTypeVariables();
for (int i = 0; i < tVars.length; i++) {
if (tVars[i].getName().equals(getName())) {
resolvedTVar = tVars[i];
break;
}
}
} else {
ResolvedMember declaring = (ResolvedMember) declaringElement;
TypeVariable[] tvrts = declaring.getTypeVariables();
for (int i = 0; i < tvrts.length; i++) {
if (tvrts[i].getName().equals(getName())) {
resolvedTVar = tvrts[i];
}
}
}
if (resolvedTVar == null) {
throw new IllegalStateException();
}
} else {
resolvedTVar = this;
}
superclass = resolvedTVar.superclass;
superInterfaces = resolvedTVar.superInterfaces;
if (superclass != null) {
ResolvedType rt = superclass.resolve(world);
superclass = rt;
}
firstbound = getFirstBound().resolve(world);
for (int i = 0; i < superInterfaces.length; i++) {
superInterfaces[i] = superInterfaces[i].resolve(world);
}
isResolved = true;
beingResolved = false;
return this;
}
public boolean canBeBoundTo(ResolvedType candidate) {
if (!isResolved) {
throw new IllegalStateException("Can't answer binding questions prior to resolving");
}
if (candidate.isGenericWildcard()) {
return true;
}
if (superclass != null && !isASubtypeOf(superclass, candidate)) {
return false;
}
for (int i = 0; i < superInterfaces.length; i++) {
if (!isASubtypeOf(superInterfaces[i], candidate)) {
return false;
}
}
return true;
}
private boolean isASubtypeOf(UnresolvedType candidateSuperType, UnresolvedType candidateSubType) {
ResolvedType superType = (ResolvedType) candidateSuperType;
ResolvedType subType = (ResolvedType) candidateSubType;
return superType.isAssignableFrom(subType);
}
public void setUpperBound(UnresolvedType superclass) {
this.firstbound = null;
this.superclass = superclass;
}
public void setAdditionalInterfaceBounds(UnresolvedType[] superInterfaces) {
this.firstbound = null;
this.superInterfaces = superInterfaces;
}
public String toDebugString() {
return getDisplayName();
}
public String getDisplayName() {
StringBuffer ret = new StringBuffer();
ret.append(name);
if (!getFirstBound().getName().equals("java.lang.Object")) {
ret.append(" extends ");
ret.append(getFirstBound().getName());
if (superInterfaces != null) {
for (int i = 0; i < superInterfaces.length; i++) {
if (!getFirstBound().equals(superInterfaces[i])) {
ret.append(" & ");
ret.append(superInterfaces[i].getName());
}
}
}
}
return ret.toString();
}
@Override
public String toString() {
return "TypeVar " + getDisplayName();
}
public String getSignature() {
StringBuffer sb = new StringBuffer();
sb.append(name);
sb.append(":");
if (superInterfaces.length == 0 || !superclass.getSignature().equals(UnresolvedType.OBJECT.getSignature())) {
sb.append(superclass.getSignature());
}
if (superInterfaces.length != 0) {
for (int i = 0; i < superInterfaces.length; i++) {
sb.append(":");
UnresolvedType iBound = superInterfaces[i];
sb.append(iBound.getSignature());
}
}
return sb.toString();
}
public String getSignatureForAttribute() {
StringBuffer sb = new StringBuffer();
sb.append(name);
sb.append(":");
if (superInterfaces.length == 0 || !superclass.getSignature().equals(UnresolvedType.OBJECT.getSignature())) {
sb.append(((ReferenceType)superclass).getSignatureForAttribute());
}
if (superInterfaces.length != 0) {
for (int i = 0; i < superInterfaces.length; i++) {
sb.append(":");
ResolvedType iBound = (ResolvedType) superInterfaces[i];
sb.append(iBound.getSignatureForAttribute());
}
}
return sb.toString();
}
public void setRank(int rank) {
this.rank = rank;
}
public int getRank() {
return rank;
}
public void setDeclaringElement(TypeVariableDeclaringElement element) {
this.declaringElement = element;
if (element instanceof UnresolvedType) {
this.declaringElementKind = TYPE;
} else {
this.declaringElementKind = METHOD;
}
}
public TypeVariableDeclaringElement getDeclaringElement() {
return declaringElement;
}
public void setDeclaringElementKind(int kind) {
this.declaringElementKind = kind;
}
public int getDeclaringElementKind() {
return declaringElementKind;
}
public void write(CompressingDataOutputStream s) throws IOException {
s.writeUTF(name);
superclass.write(s);
if (superInterfaces.length == 0) {
s.writeInt(0);
} else {
s.writeInt(superInterfaces.length);
for (int i = 0; i < superInterfaces.length; i++) {
UnresolvedType ibound = superInterfaces[i];
ibound.write(s);
}
}
}
public static TypeVariable read(VersionedDataInputStream s) throws IOException {
String name = s.readUTF();
UnresolvedType ubound = UnresolvedType.read(s);
int iboundcount = s.readInt();
UnresolvedType[] ibounds = UnresolvedType.NONE;
if (iboundcount > 0) {
ibounds = new UnresolvedType[iboundcount];
for (int i = 0; i < iboundcount; i++) {
ibounds[i] = UnresolvedType.read(s);
}
}
TypeVariable newVariable = new TypeVariable(name, ubound, ibounds);
return newVariable;
}
public String getGenericSignature() {
return "T" + name + ";";
}
public String getErasureSignature() {
return getFirstBound().getErasureSignature();
}
public UnresolvedType getSuperclass() {
return superclass;
}
public void setSuperclass(UnresolvedType superclass) {
this.firstbound = null;
this.superclass = superclass;
}
}