All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.weaver.TypeVariable Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * Copyright (c) 2005-2010 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 * ******************************************************************/
package org.aspectj.weaver;

import java.io.IOException;

/**
 * Represents a type variable with possible bounds.
 *
 * @author Adrian Colyer
 * @author Andy Clement
 */
public class TypeVariable {

	public static final TypeVariable[] NONE = new TypeVariable[0];

	// the name of the type variable as recorded in the generic signature
	private String name;
	// index
	private int rank;
	// computed as required: either ==superclass or ==superInterfaces[0] or is OBJECT
	private UnresolvedType firstbound;
	// the upper bound of the type variable. From the extends clause, eg. T extends Number
	private UnresolvedType superclass;
	// any additional upper (interface) bounds. from the extends clause, e.g. T extends Number & Comparable
	private UnresolvedType[] superInterfaces = UnresolvedType.NONE;
	// It would be nice to push this field onto the TypeVariableDeclaringElement
	// interface (a getKind()) but at the moment we don't always guarantee
	// to set the declaring element (eclipse seems to utilise the knowledge of
	// what declared the type variable, but we dont yet...)
	public static final int UNKNOWN = -1;
	public static final int METHOD = 1;
	public static final int TYPE = 2;
	// What kind of element declared this type variable?
	private int declaringElementKind = UNKNOWN;
	private TypeVariableDeclaringElement declaringElement;
	// whether or not the bounds of this type variable have been resolved
	public boolean isResolved = false;
	// Is this type variable in the process of being resolved (allows for something self-referential like Enum)
	private boolean beingResolved = false;

	/**
	 * Constructor for an unbound type variable, eg. 'T'
	 */
	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;
	}

	/**
	 * @return the first bound, either the superclass or if non is specified the first interface or if non are specified then OBJECT
	 */
	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;
	}

	/**
	 * resolve all the bounds of this type variable
	 */
	public TypeVariable resolve(World world) {
		if (isResolved) {
			return this;
		}
		if (beingResolved) {
			return this;
		}
		beingResolved = true;

		TypeVariable resolvedTVar = null;

		if (declaringElement != null) {
			// resolve by finding the real type var that we refer to...
			if (declaringElementKind == TYPE) {
				UnresolvedType declaring = (UnresolvedType) declaringElement;
				ReferenceType rd = (ReferenceType) declaring.resolve(world);
				TypeVariable[] tVars = rd.getTypeVariables();
				for (TypeVariable tVar : tVars) {
					if (tVar.getName().equals(getName())) {
						resolvedTVar = tVar;
						break;
					}
				}
			} else {
				// look for type variable on method...
				ResolvedMember declaring = (ResolvedMember) declaringElement;
				TypeVariable[] tvrts = declaring.getTypeVariables();
				for (TypeVariable tvrt : tvrts) {
					if (tvrt.getName().equals(getName())) {
						resolvedTVar = tvrt;
						// if (tvrts[i].isTypeVariableReference()) {
						// TypeVariableReferenceType tvrt = (TypeVariableReferenceType) tvrts[i].resolve(inSomeWorld);
						// TypeVariable tv = tvrt.getTypeVariable();
						// if (tv.getName().equals(getName())) resolvedTVar = tv;
						// }
					}
				}
			}

			if (resolvedTVar == null) {
				throw new IllegalStateException();
				// well, this is bad... we didn't find the type variable on the member
				// could be a separate compilation issue...
				// should issue message, this is a workaround to get us going...
				// resolvedTVar = this;
			}
		} else {
			resolvedTVar = this;
		}

		superclass = resolvedTVar.superclass;
		superInterfaces = resolvedTVar.superInterfaces;

		if (superclass != null) {
			ResolvedType rt = superclass.resolve(world);
//			 if (!superclass.isTypeVariableReference() && rt.isInterface()) {
//				 throw new IllegalStateException("Why is the type an interface? " + rt);
//			 }
			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;
	}

	/**
	 * answer true if the given type satisfies all of the bound constraints of this type variable. If type variable has not been
	 * resolved then throws IllegalStateException
	 */
	public boolean canBeBoundTo(ResolvedType candidate) {
		if (!isResolved) {
			throw new IllegalStateException("Can't answer binding questions prior to resolving");
		}

		// wildcard can accept any binding
		if (candidate.isGenericWildcard()) {
			return true;
		}

		// otherwise can be bound iff...

		// candidate is a subtype of upperBound
		if (superclass != null && !isASubtypeOf(superclass, candidate)) {
			return false;
		}
		// candidate is a subtype of all superInterfaces
		for (UnresolvedType superInterface : superInterfaces) {
			if (!isASubtypeOf(superInterface, candidate)) {
				return false;
			}
		}
		return true;
	}

	private boolean isASubtypeOf(UnresolvedType candidateSuperType, UnresolvedType candidateSubType) {
		ResolvedType superType = (ResolvedType) candidateSuperType;
		ResolvedType subType = (ResolvedType) candidateSubType;
		return superType.isAssignableFrom(subType);
	}

	// only used when resolving
	public void setUpperBound(UnresolvedType superclass) {
		// if (isResolved) {
		// throw new IllegalStateException("Why set this late?");
		// }
		this.firstbound = null;
		this.superclass = superclass;
	}

	// only used when resolving
	public void setAdditionalInterfaceBounds(UnresolvedType[] superInterfaces) {
		// if (isResolved) {
		// throw new IllegalStateException("Why set this late?");
		// }
		this.firstbound = null;
		this.superInterfaces = superInterfaces;
	}

	public String toDebugString() {
		return getDisplayName();
	}

	public String getDisplayName() {
		StringBuilder ret = new StringBuilder();
		ret.append(name);
		if (!getFirstBound().getName().equals("java.lang.Object")) {
			ret.append(" extends ");
			ret.append(getFirstBound().getName());
			if (superInterfaces != null) {
				for (UnresolvedType superInterface : superInterfaces) {
					if (!getFirstBound().equals(superInterface)) {
						ret.append(" & ");
						ret.append(superInterface.getName());
					}
				}
			}
		}
		return ret.toString();
	}

	@Override
	public String toString() {
		return "TypeVar " + getDisplayName();
	}

	/**
	 * Return complete signature, e.g. "T extends Number" would return "T:Ljava/lang/Number;" note: MAY INCLUDE P types if bounds
	 * are parameterized types
	 */
	public String getSignature() {
		StringBuilder sb = new StringBuilder();
		sb.append(name);
		sb.append(":");
		if (superInterfaces.length == 0 || !superclass.getSignature().equals(UnresolvedType.OBJECT.getSignature())) {
			sb.append(superclass.getSignature());
		}
		if (superInterfaces.length != 0) {
			for (UnresolvedType superInterface : superInterfaces) {
				sb.append(":");
				UnresolvedType iBound = superInterface;
				sb.append(iBound.getSignature());
			}
		}
		return sb.toString();
	}

	/**
	 * @return signature for inclusion in an attribute, there must be no 'P' in it signatures
	 */
	public String getSignatureForAttribute() {
		StringBuilder sb = new StringBuilder();
		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 (UnresolvedType superInterface : superInterfaces) {
				sb.append(":");
				ResolvedType iBound = (ResolvedType) superInterface;
				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() {
		// if (declaringElementKind==UNKNOWN) throw new RuntimeException("Dont know declarer of this tvar : "+this);
		return declaringElementKind;
	}

	public void write(CompressingDataOutputStream s) throws IOException {
		// name, upperbound, additionalInterfaceBounds, lowerbound
		s.writeUTF(name);
		superclass.write(s);
		if (superInterfaces.length == 0) {
			s.writeInt(0);
		} else {
			s.writeInt(superInterfaces.length);
			for (UnresolvedType ibound : superInterfaces) {
				ibound.write(s);
			}
		}
	}

	public static TypeVariable read(VersionedDataInputStream s) throws IOException {

		// if (s.getMajorVersion()>=AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {

		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;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy