/* ******************************************************************* * 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; newInterfaces = null; typeVariables = null; parameterizedInterfaces.clear(); superclassReference = new WeakReference(null); if (getDelegate() != null) { delegate.ensureConsistent(); } if (isRawType()) { 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; } }