All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Search JAR files by class name

Source code of the class ReferenceType.java part of aspectjweaver version 1.8.9

Go to download Show more of this group Show artifacts with the name aspectjweaver
        /* *******************************************************************
 * Copyright (c) 2002 Contributors
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 *     Andy Clement - June 2005 - separated out from ResolvedType
 * ******************************************************************/
package org.aspectj.weaver;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.aspectj.bridge.ISourceLocation;
import org.aspectj.weaver.World.TypeMap;
import org.aspectj.weaver.patterns.Declare;
import org.aspectj.weaver.patterns.PerClause;

/**
 * A reference type represents some 'real' type, not a primitive, not an array -
 * but a real type, for example java.util.List. Each ReferenceType has a
 * delegate that is the underlying artifact - either an eclipse artifact or a
 * bcel artifact. If the type represents a raw type (i.e. there is a generic
 * form) then the genericType field is set to point to the generic type. If it
 * is for a parameterized type then the generic type is also set to point to the
 * generic form.
 */
public class ReferenceType extends ResolvedType {

	public static final ReferenceType[] EMPTY_ARRAY = new ReferenceType[0];

	/**
	 * For generic types, this list holds references to all the derived raw and
	 * parameterized versions. We need this so that if the generic delegate is
	 * swapped during incremental compilation, the delegate of the derivatives
	 * is swapped also.
	 */
	private final List> derivativeTypes = new ArrayList>();

	/**
	 * For parameterized types (or the raw type) - this field points to the
	 * actual reference type from which they are derived.
	 */
	ReferenceType genericType = null;

	ReferenceType rawType = null; // generic types have a pointer back to their
									// raw variant (prevents GC of the raw from
									// the typemap!)

	ReferenceTypeDelegate delegate = null;
	int startPos = 0;
	int endPos = 0;

	// cached values for members
	ResolvedMember[] parameterizedMethods = null;
	ResolvedMember[] parameterizedFields = null;
	ResolvedMember[] parameterizedPointcuts = null;
	WeakReference parameterizedInterfaces = new WeakReference(
			null);
	Collection parameterizedDeclares = null;
	// Collection parameterizedTypeMungers = null;

	// During matching it can be necessary to temporary mark types as annotated.
	// For example
	// a declare @type may trigger a separate declare parents to match, and so
	// the annotation
	// is temporarily held against the referencetype, the annotation will be
	// properly
	// added to the class during weaving.
	private ResolvedType[] annotationTypes = null;
	private AnnotationAJ[] annotations = null;

	// Similarly these are temporary replacements and additions for the
	// superclass and
	// superinterfaces
	private ResolvedType newSuperclass;
	private ResolvedType[] newInterfaces;

	public ReferenceType(String signature, World world) {
		super(signature, world);
	}

	public ReferenceType(String signature, String signatureErasure, World world) {
		super(signature, signatureErasure, world);
	}

	public static ReferenceType fromTypeX(UnresolvedType tx, World world) {
		ReferenceType rt = new ReferenceType(tx.getErasureSignature(), world);
		rt.typeKind = tx.typeKind;
		return rt;
	}

	/**
	 * Constructor used when creating a parameterized type.
	 */
	public ReferenceType(ResolvedType theGenericType,
			ResolvedType[] theParameters, World aWorld) {
		super(makeParameterizedSignature(theGenericType, theParameters),
				theGenericType.signatureErasure, aWorld);
		ReferenceType genericReferenceType = (ReferenceType) theGenericType;
		this.typeParameters = theParameters;
		this.genericType = genericReferenceType;
		this.typeKind = TypeKind.PARAMETERIZED;
		this.delegate = genericReferenceType.getDelegate();
		genericReferenceType.addDependentType(this);
	}

	synchronized void addDependentType(ReferenceType dependent) {
		// checkDuplicates(dependent);
		synchronized (derivativeTypes) {
			this.derivativeTypes
					.add(new WeakReference(dependent));
		}
	}

	public void checkDuplicates(ReferenceType newRt) {
		synchronized (derivativeTypes) {
			List> forRemoval = new ArrayList>();
			for (WeakReference derivativeTypeReference : derivativeTypes) {
				ReferenceType derivativeType = derivativeTypeReference.get();
				if (derivativeType == null) {
					forRemoval.add(derivativeTypeReference);
				} else {
					if (derivativeType.getTypekind() != newRt.getTypekind()) {
						continue; // cannot be this one
					}
					if (equal2(newRt.getTypeParameters(),
							derivativeType.getTypeParameters())) {
						if (TypeMap.useExpendableMap) {
							throw new IllegalStateException();
						}
					}
				}
			}
			derivativeTypes.removeAll(forRemoval);
		}
	}

	private boolean equal2(UnresolvedType[] typeParameters,
			UnresolvedType[] resolvedParameters) {
		if (typeParameters.length != resolvedParameters.length) {
			return false;
		}
		int len = typeParameters.length;
		for (int p = 0; p < len; p++) {
			if (!typeParameters[p].equals(resolvedParameters[p])) {
				return false;
			}
		}
		return true;
	}

	@Override
	public String getSignatureForAttribute() {
		if (genericType == null || typeParameters == null) {
			return getSignature();
		}
		return makeDeclaredSignature(genericType, typeParameters);
	}

	/**
	 * Create a reference type for a generic type
	 */
	public ReferenceType(UnresolvedType genericType, World world) {
		super(genericType.getSignature(), world);
		typeKind = TypeKind.GENERIC;
		this.typeVariables = genericType.typeVariables;
	}

	@Override
	public boolean isClass() {
		return getDelegate().isClass();
	}

	@Override
	public int getCompilerVersion() {
		return getDelegate().getCompilerVersion();
	}

	@Override
	public boolean isGenericType() {
		return !isParameterizedType() && !isRawType()
				&& getDelegate().isGeneric();
	}

	public String getGenericSignature() {
		String sig = getDelegate().getDeclaredGenericSignature();
		return (sig == null) ? "" : sig;
	}

	@Override
	public AnnotationAJ[] getAnnotations() {
		return getDelegate().getAnnotations();
	}

	@Override
	public boolean hasAnnotations() {
		return getDelegate().hasAnnotations();
	}

	@Override
	public void addAnnotation(AnnotationAJ annotationX) {
		if (annotations == null) {
			annotations = new AnnotationAJ[] { annotationX };
		} else {
			AnnotationAJ[] newAnnotations = new AnnotationAJ[annotations.length + 1];
			System.arraycopy(annotations, 0, newAnnotations, 1,
					annotations.length);
			newAnnotations[0] = annotationX;
			annotations = newAnnotations;
		}
		addAnnotationType(annotationX.getType());
	}

	public boolean hasAnnotation(UnresolvedType ofType) {
		boolean onDelegate = getDelegate().hasAnnotation(ofType);
		if (onDelegate) {
			return true;
		}
		if (annotationTypes != null) {
			for (int i = 0; i < annotationTypes.length; i++) {
				if (annotationTypes[i].equals(ofType)) {
					return true;
				}
			}
		}
		return false;
	}

	private void addAnnotationType(ResolvedType ofType) {
		if (annotationTypes == null) {
			annotationTypes = new ResolvedType[1];
			annotationTypes[0] = ofType;
		} else {
			ResolvedType[] newAnnotationTypes = new ResolvedType[annotationTypes.length + 1];
			System.arraycopy(annotationTypes, 0, newAnnotationTypes, 1,
					annotationTypes.length);
			newAnnotationTypes[0] = ofType;
			annotationTypes = newAnnotationTypes;
		}
	}

	@Override
	public ResolvedType[] getAnnotationTypes() {
		if (getDelegate() == null) {
			throw new BCException("Unexpected null delegate for type "
					+ this.getName());
		}
		if (annotationTypes == null) {
			// there are no extras:
			return getDelegate().getAnnotationTypes();
		} else {
			ResolvedType[] delegateAnnotationTypes = getDelegate()
					.getAnnotationTypes();
			ResolvedType[] result = new ResolvedType[annotationTypes.length
					+ delegateAnnotationTypes.length];
			System.arraycopy(delegateAnnotationTypes, 0, result, 0,
					delegateAnnotationTypes.length);
			System.arraycopy(annotationTypes, 0, result,
					delegateAnnotationTypes.length, annotationTypes.length);
			return result;
		}
	}

	@Override
	public String getNameAsIdentifier() {
		return getRawName().replace('.', '_');
	}

	@Override
	public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
		AnnotationAJ[] axs = getDelegate().getAnnotations();
		if (axs != null) {
			for (int i = 0; i < axs.length; i++) {
				if (axs[i].getTypeSignature().equals(ofType.getSignature())) {
					return axs[i];
				}
			}
		}
		if (annotations != null) {
			String searchSig = ofType.getSignature();
			for (int i = 0; i < annotations.length; i++) {
				if (annotations[i].getTypeSignature().equals(searchSig)) {
					return annotations[i];
				}
			}
		}
		return null;
	}

	@Override
	public boolean isAspect() {
		return getDelegate().isAspect();
	}

	@Override
	public boolean isAnnotationStyleAspect() {
		return getDelegate().isAnnotationStyleAspect();
	}

	@Override
	public boolean isEnum() {
		return getDelegate().isEnum();
	}

	@Override
	public boolean isAnnotation() {
		return getDelegate().isAnnotation();
	}

	@Override
	public boolean isAnonymous() {
		return getDelegate().isAnonymous();
	}

	@Override
	public boolean isNested() {
		return getDelegate().isNested();
	}

	public ResolvedType getOuterClass() {
		return getDelegate().getOuterClass();
	}

	public String getRetentionPolicy() {
		return getDelegate().getRetentionPolicy();
	}

	@Override
	public boolean isAnnotationWithRuntimeRetention() {
		return getDelegate().isAnnotationWithRuntimeRetention();
	}

	@Override
	public boolean canAnnotationTargetType() {
		return getDelegate().canAnnotationTargetType();
	}

	@Override
	public AnnotationTargetKind[] getAnnotationTargetKinds() {
		return getDelegate().getAnnotationTargetKinds();
	}

	// true iff the statement "this = (ThisType) other" would compile
	@Override
	public boolean isCoerceableFrom(ResolvedType o) {
		ResolvedType other = o.resolve(world);

		if (this.isAssignableFrom(other) || other.isAssignableFrom(this)) {
			return true;
		}

		if (this.isParameterizedType() && other.isParameterizedType()) {
			return isCoerceableFromParameterizedType(other);
		}

		if (this.isParameterizedType() && other.isRawType()) {
			return ((ReferenceType) this.getRawType()).isCoerceableFrom(other
					.getGenericType());
		}

		if (this.isRawType() && other.isParameterizedType()) {
			return this.getGenericType().isCoerceableFrom((other.getRawType()));
		}

		if (!this.isInterface() && !other.isInterface()) {
			return false;
		}
		if (this.isFinal() || other.isFinal()) {
			return false;
		}
		// ??? needs to be Methods, not just declared methods? JLS 5.5 unclear
		ResolvedMember[] a = getDeclaredMethods();
		ResolvedMember[] b = other.getDeclaredMethods(); // ??? is this cast
		// always safe
		for (int ai = 0, alen = a.length; ai < alen; ai++) {
			for (int bi = 0, blen = b.length; bi < blen; bi++) {
				if (!b[bi].isCompatibleWith(a[ai])) {
					return false;
				}
			}
		}
		return true;
	}

	private final boolean isCoerceableFromParameterizedType(ResolvedType other) {
		if (!other.isParameterizedType()) {
			return false;
		}
		ResolvedType myRawType = getRawType();
		ResolvedType theirRawType = other.getRawType();
		if (myRawType == theirRawType
				|| myRawType.isCoerceableFrom(theirRawType)) {
			if (getTypeParameters().length == other.getTypeParameters().length) {
				// there's a chance it can be done
				ResolvedType[] myTypeParameters = getResolvedTypeParameters();
				ResolvedType[] theirTypeParameters = other
						.getResolvedTypeParameters();
				for (int i = 0; i < myTypeParameters.length; i++) {
					if (myTypeParameters[i] != theirTypeParameters[i]) {
						// thin ice now... but List may still be
						// coerceable from e.g. List
						if (myTypeParameters[i].isGenericWildcard()) {
							BoundedReferenceType wildcard = (BoundedReferenceType) myTypeParameters[i];
							if (!wildcard
									.canBeCoercedTo(theirTypeParameters[i])) {
								return false;
							}
						} else if (myTypeParameters[i]
								.isTypeVariableReference()) {
							TypeVariableReferenceType tvrt = (TypeVariableReferenceType) myTypeParameters[i];
							TypeVariable tv = tvrt.getTypeVariable();
							tv.resolve(world);
							if (!tv.canBeBoundTo(theirTypeParameters[i])) {
								return false;
							}
						} else if (theirTypeParameters[i]
								.isTypeVariableReference()) {
							TypeVariableReferenceType tvrt = (TypeVariableReferenceType) theirTypeParameters[i];
							TypeVariable tv = tvrt.getTypeVariable();
							tv.resolve(world);
							if (!tv.canBeBoundTo(myTypeParameters[i])) {
								return false;
							}
						} else if (theirTypeParameters[i].isGenericWildcard()) {
							BoundedReferenceType wildcard = (BoundedReferenceType) theirTypeParameters[i];
							if (!wildcard.canBeCoercedTo(myTypeParameters[i])) {
								return false;
							}
						} else {
							return false;
						}
					}
				}
				return true;
			}
			// } else {
			// // we do this walk for situations like the following:
			// // Base, Sub extends Base
			// // is Sub coerceable from Base ???
			// for (Iterator i = getDirectSupertypes(); i.hasNext();) {
			// ReferenceType parent = (ReferenceType) i.next();
			// if (parent.isCoerceableFromParameterizedType(other))
			// return true;
			// }
		}
		return false;
	}

	@Override
	public boolean isAssignableFrom(ResolvedType other) {
		return isAssignableFrom(other, false);
	}

	// TODO rewrite this method - it is a terrible mess

	// true iff the statement "this = other" would compile.
	@Override
	public boolean isAssignableFrom(ResolvedType other, boolean allowMissing) {
		if (other.isPrimitiveType()) {
			if (!world.isInJava5Mode()) {
				return false;
			}
			if (ResolvedType.validBoxing.contains(this.getSignature()
					+ other.getSignature())) {
				return true;
			}
		}
		if (this == other) {
			return true;
		}

		if (this.getSignature().equals("Ljava/lang/Object;")) {
			return true;
		}

		if (!isTypeVariableReference()
				&& other.getSignature().equals("Ljava/lang/Object;")) {
			return false;
		}

		boolean thisRaw = this.isRawType();
		if (thisRaw && other.isParameterizedOrGenericType()) {
			return isAssignableFrom(other.getRawType());
		}

		boolean thisGeneric = this.isGenericType();
		if (thisGeneric && other.isParameterizedOrRawType()) {
			return isAssignableFrom(other.getGenericType());
		}

		if (this.isParameterizedType()) {
			// look at wildcards...
			if (((ReferenceType) this.getRawType()).isAssignableFrom(other)) {
				boolean wildcardsAllTheWay = true;
				ResolvedType[] myParameters = this.getResolvedTypeParameters();
				for (int i = 0; i < myParameters.length; i++) {
					if (!myParameters[i].isGenericWildcard()) {
						wildcardsAllTheWay = false;
					} else {
						BoundedReferenceType boundedRT = (BoundedReferenceType) myParameters[i];
						if (boundedRT.isExtends() || boundedRT.isSuper()) {
							wildcardsAllTheWay = false;
						}
					}
				}
				if (wildcardsAllTheWay && !other.isParameterizedType()) {
					return true;
				}
				// we have to match by parameters one at a time
				ResolvedType[] theirParameters = other
						.getResolvedTypeParameters();
				boolean parametersAssignable = true;
				if (myParameters.length == theirParameters.length) {
					for (int i = 0; i < myParameters.length
							&& parametersAssignable; i++) {
						if (myParameters[i] == theirParameters[i]) {
							continue;
						}
						// dont do this: pr253109
						// if
						// (myParameters[i].isAssignableFrom(theirParameters[i],
						// allowMissing)) {
						// continue;
						// }
						ResolvedType mp = myParameters[i];
						ResolvedType tp = theirParameters[i];
						if (mp.isParameterizedType()
								&& tp.isParameterizedType()) {
							if (mp.getGenericType().equals(tp.getGenericType())) {
								UnresolvedType[] mtps = mp.getTypeParameters();
								UnresolvedType[] ttps = tp.getTypeParameters();
								for (int ii = 0; ii < mtps.length; ii++) {
									if (mtps[ii].isTypeVariableReference()
											&& ttps[ii]
													.isTypeVariableReference()) {
										TypeVariable mtv = ((TypeVariableReferenceType) mtps[ii])
												.getTypeVariable();
										boolean b = mtv
												.canBeBoundTo((ResolvedType) ttps[ii]);
										if (!b) {// TODO incomplete testing here
													// I think
											parametersAssignable = false;
											break;
										}
									} else {
										parametersAssignable = false;
										break;
									}
								}
								continue;
							} else {
								parametersAssignable = false;
								break;
							}
						}
						if (myParameters[i].isTypeVariableReference()
								&& theirParameters[i].isTypeVariableReference()) {
							TypeVariable myTV = ((TypeVariableReferenceType) myParameters[i])
									.getTypeVariable();
							// TypeVariable theirTV =
							// ((TypeVariableReferenceType)
							// theirParameters[i]).getTypeVariable();
							boolean b = myTV.canBeBoundTo(theirParameters[i]);
							if (!b) {// TODO incomplete testing here I think
								parametersAssignable = false;
								break;
							} else {
								continue;
							}
						}
						if (!myParameters[i].isGenericWildcard()) {
							parametersAssignable = false;
							break;
						} else {
							BoundedReferenceType wildcardType = (BoundedReferenceType) myParameters[i];
							if (!wildcardType.alwaysMatches(theirParameters[i])) {
								parametersAssignable = false;
								break;
							}
						}
					}
				} else {
					parametersAssignable = false;
				}
				if (parametersAssignable) {
					return true;
				}
			}
		}

		// eg this=T other=Ljava/lang/Object;
		if (isTypeVariableReference() && !other.isTypeVariableReference()) {
			TypeVariable aVar = ((TypeVariableReference) this)
					.getTypeVariable();
			return aVar.resolve(world).canBeBoundTo(other);
		}

		if (other.isTypeVariableReference()) {
			TypeVariableReferenceType otherType = (TypeVariableReferenceType) other;
			if (this instanceof TypeVariableReference) {
				return ((TypeVariableReference) this)
						.getTypeVariable()
						.resolve(world)
						.canBeBoundTo(
								otherType.getTypeVariable().getFirstBound()
										.resolve(world));// pr171952
				// return
				// ((TypeVariableReference)this).getTypeVariable()==otherType
				// .getTypeVariable();
			} else {
				// FIXME asc should this say canBeBoundTo??
				return this.isAssignableFrom(otherType.getTypeVariable()
						.getFirstBound().resolve(world));
			}
		}

		if (allowMissing && other.isMissing()) {
			return false;
		}

		ResolvedType[] interfaces = other.getDeclaredInterfaces();
		for (ResolvedType intface : interfaces) {
			boolean b;
			if (thisRaw && intface.isParameterizedOrGenericType()) {
				b = this.isAssignableFrom(intface.getRawType(), allowMissing);
			} else {
				b = this.isAssignableFrom(intface, allowMissing);
			}
			if (b) {
				return true;
			}
		}
		ResolvedType superclass = other.getSuperclass();
		if (superclass != null) {
			boolean b;
			if (thisRaw && superclass.isParameterizedOrGenericType()) {
				b = this.isAssignableFrom(superclass.getRawType(), allowMissing);
			} else {
				b = this.isAssignableFrom(superclass, allowMissing);
			}
			if (b) {
				return true;
			}
		}
		return false;
	}

	@Override
	public ISourceContext getSourceContext() {
		return getDelegate().getSourceContext();
	}

	@Override
	public ISourceLocation getSourceLocation() {
		ISourceContext isc = getDelegate().getSourceContext();
		return isc.makeSourceLocation(new Position(startPos, endPos));
	}

	@Override
	public boolean isExposedToWeaver() {
		return (getDelegate() == null) || delegate.isExposedToWeaver();
	}

	@Override
	public WeaverStateInfo getWeaverState() {
		return getDelegate().getWeaverState();
	}

	@Override
	public ResolvedMember[] getDeclaredFields() {
		if (parameterizedFields != null) {
			return parameterizedFields;
		}
		if (isParameterizedType() || isRawType()) {
			ResolvedMember[] delegateFields = getDelegate().getDeclaredFields();
			parameterizedFields = new ResolvedMember[delegateFields.length];
			for (int i = 0; i < delegateFields.length; i++) {
				parameterizedFields[i] = delegateFields[i].parameterizedWith(
						getTypesForMemberParameterization(), this,
						isParameterizedType());
			}
			return parameterizedFields;
		} else {
			return getDelegate().getDeclaredFields();
		}
	}

	/**
	 * Find out from the generic signature the true signature of any interfaces
	 * I implement. If I am parameterized, these may then need to be
	 * parameterized before returning.
	 */
	@Override
	public ResolvedType[] getDeclaredInterfaces() {
		ResolvedType[] interfaces = parameterizedInterfaces.get();
		if (interfaces != null) {
			return interfaces;
		}
		ResolvedType[] delegateInterfaces = getDelegate()
				.getDeclaredInterfaces();
		if (isRawType()) {
			if (newInterfaces != null) {// debug 375777
				throw new IllegalStateException(
						"The raw type should never be accumulating new interfaces, they should be on the generic type.  Type is "
								+ this.getName());
			}
			ResolvedType[] newInterfacesFromGenericType = genericType.newInterfaces;
			if (newInterfacesFromGenericType != null) {
				ResolvedType[] extraInterfaces = new ResolvedType[delegateInterfaces.length
						+ newInterfacesFromGenericType.length];
				System.arraycopy(delegateInterfaces, 0, extraInterfaces, 0,
						delegateInterfaces.length);
				System.arraycopy(newInterfacesFromGenericType, 0,
						extraInterfaces, delegateInterfaces.length,
						newInterfacesFromGenericType.length);
				delegateInterfaces = extraInterfaces;
			}
		} else if (newInterfaces != null) {
			// OPTIMIZE does this part of the method trigger often?
			ResolvedType[] extraInterfaces = new ResolvedType[delegateInterfaces.length
					+ newInterfaces.length];
			System.arraycopy(delegateInterfaces, 0, extraInterfaces, 0,
					delegateInterfaces.length);
			System.arraycopy(newInterfaces, 0, extraInterfaces,
					delegateInterfaces.length, newInterfaces.length);

			delegateInterfaces = extraInterfaces;
		}
		if (isParameterizedType()) {
			// UnresolvedType[] paramTypes =
			// getTypesForMemberParameterization();
			interfaces = new ResolvedType[delegateInterfaces.length];
			for (int i = 0; i < delegateInterfaces.length; i++) {
				// We may have to sub/super set the set of parametertypes if the
				// implemented interface
				// needs more or less than this type does. (pr124803/pr125080)

				if (delegateInterfaces[i].isParameterizedType()) {
					interfaces[i] = delegateInterfaces[i].parameterize(
							getMemberParameterizationMap()).resolve(world);
				} else {
					interfaces[i] = delegateInterfaces[i];
				}
			}
			parameterizedInterfaces = new WeakReference(
					interfaces);
			return interfaces;
		} else if (isRawType()) {
			UnresolvedType[] paramTypes = getTypesForMemberParameterization();
			interfaces = new ResolvedType[delegateInterfaces.length];
			for (int i = 0, max = interfaces.length; i < max; i++) {
				interfaces[i] = delegateInterfaces[i];
				if (interfaces[i].isGenericType()) {
					// a generic supertype of a raw type is replaced by its raw
					// equivalent
					interfaces[i] = interfaces[i].getRawType().resolve(
							getWorld());
				} else if (interfaces[i].isParameterizedType()) {
					// a parameterized supertype collapses any type vars to
					// their upper bounds
					UnresolvedType[] toUseForParameterization = determineThoseTypesToUse(
							interfaces[i], paramTypes);
					interfaces[i] = interfaces[i]
							.parameterizedWith(toUseForParameterization);
				}
			}
			parameterizedInterfaces = new WeakReference(
					interfaces);
			return interfaces;
		}
		if (getDelegate().isCacheable()) {
			parameterizedInterfaces = new WeakReference(
					delegateInterfaces);
		}
		return delegateInterfaces;
	}

	/**
	 * It is possible this type has multiple type variables but the interface we
	 * are about to parameterize only uses a subset - this method determines the
	 * subset to use by looking at the type variable names used. For example:
	 * 
	 * class Foo implements SuperInterface {}
	 *  where 
	 * interface SuperInterface {}
	 *  In that example, a use of the 'Foo' raw type should know that it
	 * implements the SuperInterface.
	 */
	private UnresolvedType[] determineThoseTypesToUse(
			ResolvedType parameterizedInterface, UnresolvedType[] paramTypes) {
		// What are the type parameters for the supertype?
		UnresolvedType[] tParms = parameterizedInterface.getTypeParameters();
		UnresolvedType[] retVal = new UnresolvedType[tParms.length];

		// Go through the supertypes type parameters, if any of them is a type
		// variable, use the
		// real type variable on the declaring type.

		// it is possibly overkill to look up the type variable - ideally the
		// entry in the type parameter list for the
		// interface should be the a ref to the type variable in the current
		// type ... but I'm not 100% confident right now.
		for (int i = 0; i < tParms.length; i++) {
			UnresolvedType tParm = tParms[i];
			if (tParm.isTypeVariableReference()) {
				TypeVariableReference tvrt = (TypeVariableReference) tParm;
				TypeVariable tv = tvrt.getTypeVariable();
				int rank = getRank(tv.getName());
				// -1 probably means it is a reference to a type variable on the
				// outer generic type (see pr129566)
				if (rank != -1) {
					retVal[i] = paramTypes[rank];
				} else {
					retVal[i] = tParms[i];
				}
			} else {
				retVal[i] = tParms[i];
			}

		}
		return retVal;
	}

	/**
	 * Returns the position within the set of type variables for this type for
	 * the specified type variable name. Returns -1 if there is no type variable
	 * with the specified name.
	 */
	private int getRank(String tvname) {
		TypeVariable[] thisTypesTVars = getGenericType().getTypeVariables();
		for (int i = 0; i < thisTypesTVars.length; i++) {
			TypeVariable tv = thisTypesTVars[i];
			if (tv.getName().equals(tvname)) {
				return i;
			}
		}
		return -1;
	}

	@Override
	public ResolvedMember[] getDeclaredMethods() {
		if (parameterizedMethods != null) {
			return parameterizedMethods;
		}
		if (isParameterizedType() || isRawType()) {
			ResolvedMember[] delegateMethods = getDelegate()
					.getDeclaredMethods();
			UnresolvedType[] parameters = getTypesForMemberParameterization();
			parameterizedMethods = new ResolvedMember[delegateMethods.length];
			for (int i = 0; i < delegateMethods.length; i++) {
				parameterizedMethods[i] = delegateMethods[i].parameterizedWith(
						parameters, this, isParameterizedType());
			}
			return parameterizedMethods;
		} else {
			return getDelegate().getDeclaredMethods();
		}
	}

	@Override
	public ResolvedMember[] getDeclaredPointcuts() {
		if (parameterizedPointcuts != null) {
			return parameterizedPointcuts;
		}
		if (isParameterizedType()) {
			ResolvedMember[] delegatePointcuts = getDelegate()
					.getDeclaredPointcuts();
			parameterizedPointcuts = new ResolvedMember[delegatePointcuts.length];
			for (int i = 0; i < delegatePointcuts.length; i++) {
				parameterizedPointcuts[i] = delegatePointcuts[i]
						.parameterizedWith(getTypesForMemberParameterization(),
								this, isParameterizedType());
			}
			return parameterizedPointcuts;
		} else {
			return getDelegate().getDeclaredPointcuts();
		}
	}

	private UnresolvedType[] getTypesForMemberParameterization() {
		UnresolvedType[] parameters = null;
		if (isParameterizedType()) {
			parameters = getTypeParameters();
		} else if (isRawType()) {
			// raw type, use upper bounds of type variables on generic type
			TypeVariable[] tvs = getGenericType().getTypeVariables();
			parameters = new UnresolvedType[tvs.length];
			for (int i = 0; i < tvs.length; i++) {
				parameters[i] = tvs[i].getFirstBound();
			}
		}
		return parameters;
	}

	@Override
	public TypeVariable[] getTypeVariables() {
		if (typeVariables == null) {
			typeVariables = getDelegate().getTypeVariables();
			for (int i = 0; i < this.typeVariables.length; i++) {
				typeVariables[i].resolve(world);
			}
		}
		return typeVariables;
	}

	@Override
	public PerClause getPerClause() {
		PerClause pclause = getDelegate().getPerClause();
		if (pclause != null && isParameterizedType()) { // could cache the
														// result here...
			Map parameterizationMap = getAjMemberParameterizationMap();
			pclause = (PerClause) pclause.parameterizeWith(parameterizationMap,
					world);
		}
		return pclause;
	}

	@Override
	public Collection getDeclares() {
		if (parameterizedDeclares != null) {
			return parameterizedDeclares;
		}
		Collection declares = null;
		if (ajMembersNeedParameterization()) {
			Collection genericDeclares = getDelegate().getDeclares();
			parameterizedDeclares = new ArrayList();
			Map parameterizationMap = getAjMemberParameterizationMap();
			for (Declare declareStatement : genericDeclares) {
				parameterizedDeclares.add(declareStatement.parameterizeWith(
						parameterizationMap, world));
			}
			declares = parameterizedDeclares;
		} else {
			declares = getDelegate().getDeclares();
		}
		for (Declare d : declares) {
			d.setDeclaringType(this);
		}
		return declares;
	}

	@Override
	public Collection getTypeMungers() {
		return getDelegate().getTypeMungers();
	}

	@Override
	public Collection getPrivilegedAccesses() {
		return getDelegate().getPrivilegedAccesses();
	}

	@Override
	public int getModifiers() {
		return getDelegate().getModifiers();
	}

	WeakReference superclassReference = new WeakReference(
			null);

	@Override
	public ResolvedType getSuperclass() {
		ResolvedType ret = null;// superclassReference.get();
		// if (ret != null) {
		// return ret;
		// }
		if (newSuperclass != null) {
			if (this.isParameterizedType()
					&& newSuperclass.isParameterizedType()) {
				return newSuperclass.parameterize(
						getMemberParameterizationMap()).resolve(getWorld());
			}
			if (getDelegate().isCacheable()) {
				superclassReference = new WeakReference(ret);
			}
			return newSuperclass;
		}
		try {
			world.setTypeVariableLookupScope(this);
			ret = getDelegate().getSuperclass();
		} finally {
			world.setTypeVariableLookupScope(null);
		}
		if (this.isParameterizedType() && ret.isParameterizedType()) {
			ret = ret.parameterize(getMemberParameterizationMap()).resolve(
					getWorld());
		}
		if (getDelegate().isCacheable()) {
			superclassReference = new WeakReference(ret);
		}
		return ret;
	}

	public ReferenceTypeDelegate getDelegate() {
		return delegate;
	}

	public void setDelegate(ReferenceTypeDelegate delegate) {
		// Don't copy from BcelObjectType to EclipseSourceType - the context may
		// be tidied (result null'd) after previous weaving
		if (this.delegate != null
				&& this.delegate.copySourceContext()
				&& this.delegate.getSourceContext() != SourceContextImpl.UNKNOWN_SOURCE_CONTEXT) {
			((AbstractReferenceTypeDelegate) delegate)
					.setSourceContext(this.delegate.getSourceContext());
		}
		this.delegate = delegate;
		synchronized (derivativeTypes) {
			List> forRemoval = new ArrayList>();
			for (WeakReference derivativeRef : derivativeTypes) {
				ReferenceType derivative = derivativeRef.get();
				if (derivative != null) {
					derivative.setDelegate(delegate);
				} else {
					forRemoval.add(derivativeRef);
				}
			}
			derivativeTypes.removeAll(forRemoval);
		}

		// If we are raw, we have a generic type - we should ensure it uses the
		// same delegate
		if (isRawType() && getGenericType() != null) {
			ReferenceType genType = (ReferenceType) getGenericType();
			if (genType.getDelegate() != delegate) { // avoids circular updates
				genType.setDelegate(delegate);
			}
		}
		clearParameterizationCaches();
		ensureConsistent();
	}

	private void clearParameterizationCaches() {
		parameterizedFields = null;
		parameterizedInterfaces.clear();
		parameterizedMethods = null;
		parameterizedPointcuts = null;
		superclassReference = new WeakReference(null);
	}

	public int getEndPos() {
		return endPos;
	}

	public int getStartPos() {
		return startPos;
	}

	public void setEndPos(int endPos) {
		this.endPos = endPos;
	}

	public void setStartPos(int startPos) {
		this.startPos = startPos;
	}

	@Override
	public boolean doesNotExposeShadowMungers() {
		return getDelegate().doesNotExposeShadowMungers();
	}

	public String getDeclaredGenericSignature() {
		return getDelegate().getDeclaredGenericSignature();
	}

	public void setGenericType(ReferenceType rt) {
		genericType = rt;
		// Should we 'promote' this reference type from simple to raw?
		// makes sense if someone is specifying that it has a generic form
		if (typeKind == TypeKind.SIMPLE) {
			typeKind = TypeKind.RAW;
			signatureErasure = signature;
			if (newInterfaces != null) { // debug 375777
				throw new IllegalStateException(
						"Simple type promoted to raw, but simple type had new interfaces/superclass.  Type is "
								+ this.getName());
			}
		}
		if (typeKind == TypeKind.RAW) {
			genericType.addDependentType(this);
		}
		if (isRawType()) {
			genericType.rawType = this;
		}
		if (this.isRawType() && rt.isRawType()) {
			new RuntimeException(
					"PR341926 diagnostics: Incorrect setup for a generic type, raw type should not point to raw: "
							+ this.getName()).printStackTrace();
		}
	}

	public void demoteToSimpleType() {
		genericType = null;
		typeKind = TypeKind.SIMPLE;
		signatureErasure = null;
	}

	@Override
	public ReferenceType getGenericType() {
		if (isGenericType()) {
			return this;
		}
		return genericType;
	}

	/**
	 * a parameterized signature starts with a "P" in place of the "L", see the
	 * comment on signatures in UnresolvedType.
	 * 
	 * @param aGenericType
	 * @param someParameters
	 * @return
	 */
	private static String makeParameterizedSignature(ResolvedType aGenericType,
			ResolvedType[] someParameters) {
		String rawSignature = aGenericType.getErasureSignature();
		StringBuffer ret = new StringBuffer();
		ret.append(PARAMETERIZED_TYPE_IDENTIFIER);
		ret.append(rawSignature.substring(1, rawSignature.length() - 1));
		ret.append("<");
		for (int i = 0; i < someParameters.length; i++) {
			ret.append(someParameters[i].getSignature());
		}
		ret.append(">;");
		return ret.toString();
	}

	private static String makeDeclaredSignature(ResolvedType aGenericType,
			UnresolvedType[] someParameters) {
		StringBuffer ret = new StringBuffer();
		String rawSig = aGenericType.getErasureSignature();
		ret.append(rawSig.substring(0, rawSig.length() - 1));
		ret.append("<");
		for (int i = 0; i < someParameters.length; i++) {
			if (someParameters[i] instanceof ReferenceType) {
				ret.append(((ReferenceType) someParameters[i])
						.getSignatureForAttribute());
			} else if (someParameters[i] instanceof Primitive) {
				ret.append(((Primitive) someParameters[i])
						.getSignatureForAttribute());
			} else {
				throw new IllegalStateException(
						"DebugFor325731: expected a ReferenceType or Primitive but was "
								+ someParameters[i] + " of type "
								+ someParameters[i].getClass().getName());
			}
		}
		ret.append(">;");
		return ret.toString();
	}

	@Override
	public void ensureConsistent() {
		annotations = null;
		annotationTypes = null;
		newSuperclass = null;
		bits = 0; // clears the hierarchy complete tag (amongst other things)
		newInterfaces = null;
		typeVariables = null;
		parameterizedInterfaces.clear();
		superclassReference = new WeakReference(null);
		if (getDelegate() != null) {
			delegate.ensureConsistent();
		}
		if (isParameterizedOrRawType()) {
			ReferenceType genericType = getGenericType();
			if (genericType != null) {
				genericType.ensureConsistent();
			}
		}
	}

	@Override
	public void addParent(ResolvedType newParent) {
		if (this.isRawType()) {
			throw new IllegalStateException(
					"The raw type should never be accumulating new interfaces, they should be on the generic type.  Type is "
							+ this.getName());
		}
		if (newParent.isClass()) {
			newSuperclass = newParent;
			superclassReference = new WeakReference(null);
		} else {
			if (newInterfaces == null) {
				newInterfaces = new ResolvedType[1];
				newInterfaces[0] = newParent;
			} else {
				ResolvedType[] existing = getDelegate().getDeclaredInterfaces();
				if (existing != null) {
					for (int i = 0; i < existing.length; i++) {
						if (existing[i].equals(newParent)) {
							return; // already has this interface
						}
					}
				}
				ResolvedType[] newNewInterfaces = new ResolvedType[newInterfaces.length + 1];
				System.arraycopy(newInterfaces, 0, newNewInterfaces, 1,
						newInterfaces.length);
				newNewInterfaces[0] = newParent;
				newInterfaces = newNewInterfaces;
			}
			if (this.isGenericType()) {
				synchronized (derivativeTypes) {
					for (WeakReference derivativeTypeRef : derivativeTypes) {
						ReferenceType derivativeType = derivativeTypeRef.get();
						if (derivativeType != null) {
							derivativeType.parameterizedInterfaces.clear();
						}
					}
				}
			}
			parameterizedInterfaces.clear();
		}
	}

	private boolean equal(UnresolvedType[] typeParameters,
			ResolvedType[] resolvedParameters) {
		if (typeParameters.length != resolvedParameters.length) {
			return false;
		}
		int len = typeParameters.length;
		for (int p = 0; p < len; p++) {
			if (!typeParameters[p].equals(resolvedParameters[p])) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Look for a derivative type with the specified type parameters. This can
	 * avoid creating an unnecessary new (duplicate) with the same information
	 * in it. This method also cleans up any reference entries that have been
	 * null'd by a GC.
	 * 
	 * @param typeParameters
	 *            the type parameters to use when searching for the derivative
	 *            type.
	 * @return an existing derivative type or null if there isn't one
	 */
	public ReferenceType findDerivativeType(ResolvedType[] typeParameters) {
		synchronized (derivativeTypes) {
			List> forRemoval = new ArrayList>();
			for (WeakReference derivativeTypeRef : derivativeTypes) {
				ReferenceType derivativeType = derivativeTypeRef.get();
				if (derivativeType == null) {
					forRemoval.add(derivativeTypeRef);
				} else {
					if (derivativeType.isRawType()) {
						continue;
					}
					if (equal(derivativeType.typeParameters, typeParameters)) {
						return derivativeType; // this escape route wont remove
												// the empty refs
					}
				}
			}
			derivativeTypes.removeAll(forRemoval);
		}
		return null;
	}

	public boolean hasNewInterfaces() {
		return newInterfaces != null;
	}

}




© 2018 Weber Informatics LLC