|
|
@@ -26,9 +26,9 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
|
|
|
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
|
|
@@ -46,12 +46,23 @@ import org.aspectj.weaver.Shadow; |
|
|
|
public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
protected TypeReference onType; |
|
|
|
protected ReferenceBinding onTypeBinding; |
|
|
|
protected List phantomTypeVariableToRealIndex; |
|
|
|
|
|
|
|
protected ResolvedTypeMunger munger; |
|
|
|
protected int declaredModifiers; |
|
|
|
protected char[] declaredSelector; |
|
|
|
|
|
|
|
/** |
|
|
|
* If targetting a generic type and wanting to use its type variables, an ITD can use an alternative name for |
|
|
|
* them. This is a list of strings representing the alternative names - the position in the list is used to |
|
|
|
* match it to the real type variable in the target generic type. |
|
|
|
*/ |
|
|
|
protected List typeVariableAliases; |
|
|
|
|
|
|
|
/** |
|
|
|
* When set to true, the scope hierarchy for the field/method declaration has been correctly modified to |
|
|
|
* include an intertypescope which resolves things relative to the targetted type. |
|
|
|
*/ |
|
|
|
private boolean scopeSetup = false; |
|
|
|
|
|
|
|
// XXXAJ5 - When the compiler is changed, these will exist somewhere in it... |
|
|
|
private final static short ACC_ANNOTATION = 0x2000; |
|
|
|
private final static short ACC_ENUM = 0x4000; |
|
|
@@ -59,9 +70,14 @@ public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
|
|
|
|
public InterTypeDeclaration(CompilationResult result, TypeReference onType) { |
|
|
|
super(result); |
|
|
|
this.onType = onType; |
|
|
|
setOnType(onType); |
|
|
|
modifiers = AccPublic | AccStatic; |
|
|
|
} |
|
|
|
|
|
|
|
public void setOnType(TypeReference onType) { |
|
|
|
this.onType = onType; |
|
|
|
determineTypeVariableAliases(); |
|
|
|
} |
|
|
|
|
|
|
|
public void setDeclaredModifiers(int modifiers) { |
|
|
|
this.declaredModifiers = modifiers; |
|
|
@@ -108,14 +124,16 @@ public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
public void resolve(ClassScope upperScope) { |
|
|
|
if (ignoreFurtherInvestigation) return; |
|
|
|
|
|
|
|
|
|
|
|
ClassScope newParent = new InterTypeScope(upperScope, onTypeBinding); |
|
|
|
scope.parent = newParent; |
|
|
|
this.scope.isStatic = Modifier.isStatic(declaredModifiers); |
|
|
|
if (!scopeSetup) { |
|
|
|
ClassScope newParent = new InterTypeScope(upperScope, onTypeBinding,typeVariableAliases); |
|
|
|
scope.parent = newParent; |
|
|
|
this.scope.isStatic = Modifier.isStatic(declaredModifiers); |
|
|
|
scopeSetup = true; |
|
|
|
} |
|
|
|
fixSuperCallsForInterfaceContext(upperScope); |
|
|
|
if (ignoreFurtherInvestigation) return; |
|
|
|
|
|
|
|
super.resolve(newParent); |
|
|
|
super.resolve((ClassScope)scope.parent);//newParent); |
|
|
|
fixSuperCallsInBody(); |
|
|
|
} |
|
|
|
|
|
|
@@ -140,7 +158,9 @@ public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
} |
|
|
|
|
|
|
|
protected void resolveOnType(ClassScope classScope) { |
|
|
|
checkSpec(); |
|
|
|
checkSpec(); |
|
|
|
// If they did supply a parameterized single type reference, we need to do |
|
|
|
// some extra checks... |
|
|
|
if (onType instanceof ParameterizedSingleTypeReference) { |
|
|
|
resolveTypeParametersForITDOnGenericType(classScope); |
|
|
|
} else { |
|
|
@@ -153,23 +173,15 @@ public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Here we build a map from the 'names' the user specified in the target type for their |
|
|
|
* ITD to the positions of the real type variables in the target generic type. This will |
|
|
|
* enable us later (when parameterizing the ITD in the InterTypeMemberFinder) to modify |
|
|
|
* anywhere else the declaration uses these same letters to the correct type variable |
|
|
|
* in the generic type. |
|
|
|
* |
|
|
|
* This method also performs some checks to verify the ITD is well-formed. |
|
|
|
* Transform the parameterized type binding (e.g. SomeType<A,B,C>) to a |
|
|
|
* real type (e.g. SomeType). The only kind of parameterization allowed |
|
|
|
* is with type variables and those are references to type variables on |
|
|
|
* the target type. Once we have worked out the base generic type intended |
|
|
|
* then we do lots of checks to verify the declaration was well formed. |
|
|
|
*/ |
|
|
|
private void resolveTypeParametersForITDOnGenericType(ClassScope classScope) { |
|
|
|
// we have to resolve this to the base type, and in the process |
|
|
|
// check that the number of type variables matches. |
|
|
|
// Then we work out how the letters in the ITD map onto the letters in |
|
|
|
// the type declaration and swap them. |
|
|
|
|
|
|
|
// we need to build a map from type variable names to arguments in the real generic type |
|
|
|
|
|
|
|
TypeReference original = onType; |
|
|
|
|
|
|
|
// Collapse the parameterized reference to its generic type |
|
|
|
ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) onType; |
|
|
|
long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd; |
|
|
|
onType = new SingleTypeReference(pref.token,pos); |
|
|
@@ -180,9 +192,11 @@ public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
ignoreFurtherInvestigation = true; |
|
|
|
} |
|
|
|
|
|
|
|
int aliasCount = (typeVariableAliases==null?0:typeVariableAliases.size()); |
|
|
|
|
|
|
|
// Cannot specify a parameterized target type for the ITD if the target |
|
|
|
// type is not generic. |
|
|
|
if (typeParameters.length!=0 && !onTypeBinding.isGenericType()) { |
|
|
|
if (aliasCount!=0 && !onTypeBinding.isGenericType()) { |
|
|
|
scope.problemReporter().signalError(sourceStart,sourceEnd, |
|
|
|
"Type parameters can not be specified in the ITD target type - the target type "+onTypeBinding.debugName()+" is not generic."); |
|
|
|
ignoreFurtherInvestigation = true; |
|
|
@@ -190,38 +204,42 @@ public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
} |
|
|
|
|
|
|
|
// Check they have supplied the right number of type parameters on the ITD target type |
|
|
|
if (onTypeBinding.typeVariables().length != typeParameters.length) { |
|
|
|
scope.problemReporter().signalError(sourceStart, sourceEnd, |
|
|
|
"Incorrect number of type parameters supplied. The generic type "+onTypeBinding.debugName()+" has "+ |
|
|
|
onTypeBinding.typeVariables().length+" type parameters, not "+typeParameters.length+"."); |
|
|
|
ignoreFurtherInvestigation = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// check if they used stupid names for type variables |
|
|
|
for (int i = 0; i < typeParameters.length; i++) { |
|
|
|
TypeParameter array_element = typeParameters[i]; |
|
|
|
SingleTypeReference str = new SingleTypeReference(array_element.name,0); |
|
|
|
TypeBinding tb = str.getTypeBindingPublic(classScope); |
|
|
|
if (tb!=null && !(tb instanceof ProblemReferenceBinding)) { |
|
|
|
scope.problemReporter().signalError(sourceStart,sourceEnd, |
|
|
|
"Intertype declarations can only be made on the generic type, not on a parameterized type. The name '"+ |
|
|
|
CharOperation.charToString(array_element.name)+"' cannot be used as a type parameter, since it refers to a real type."); |
|
|
|
if (aliasCount>0) { |
|
|
|
if (onTypeBinding.typeVariables().length != aliasCount) { // typeParameters.length) { phantom contains the fake ones from the ontype, typeparameters will also include extra things if it is a generic method |
|
|
|
scope.problemReporter().signalError(sourceStart, sourceEnd, |
|
|
|
"Incorrect number of type parameters supplied. The generic type "+onTypeBinding.debugName()+" has "+ |
|
|
|
onTypeBinding.typeVariables().length+" type parameters, not "+aliasCount+"."); |
|
|
|
ignoreFurtherInvestigation = true; |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
TypeVariableBinding[] tVarsInGenericType = onTypeBinding.typeVariables(); |
|
|
|
phantomTypeVariableToRealIndex = new ArrayList(); /* Name>GenericTypeVariablePosition */ |
|
|
|
TypeReference[] targs = pref.typeArguments; |
|
|
|
if (targs!=null) { |
|
|
|
for (int i = 0; i < targs.length; i++) { |
|
|
|
TypeReference tref = targs[i]; |
|
|
|
phantomTypeVariableToRealIndex.add(CharOperation.toString(tref.getTypeName()));//tVarsInGenericType[i]); |
|
|
|
} |
|
|
|
// check if they used stupid names for type variables |
|
|
|
if (aliasCount>0) { |
|
|
|
for (int i = 0; i < aliasCount; i++) { |
|
|
|
String array_element = (String)typeVariableAliases.get(i); |
|
|
|
SingleTypeReference str = new SingleTypeReference(array_element.toCharArray(),0); |
|
|
|
TypeBinding tb = str.getTypeBindingPublic(classScope); |
|
|
|
if (tb!=null && !(tb instanceof ProblemReferenceBinding)) { |
|
|
|
scope.problemReporter().signalError(sourceStart,sourceEnd, |
|
|
|
"Intertype declarations can only be made on the generic type, not on a parameterized type. The name '"+ |
|
|
|
array_element+"' cannot be used as a type parameter, since it refers to a real type."); |
|
|
|
ignoreFurtherInvestigation = true; |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// TypeVariableBinding[] tVarsInGenericType = onTypeBinding.typeVariables(); |
|
|
|
// typeVariableAliases = new ArrayList(); /* Name>GenericTypeVariablePosition */ // FIXME ASC DONT THINK WE NEED TO BUILD IT HERE AS WELL... |
|
|
|
// TypeReference[] targs = pref.typeArguments; |
|
|
|
// if (targs!=null) { |
|
|
|
// for (int i = 0; i < targs.length; i++) { |
|
|
|
// TypeReference tref = targs[i]; |
|
|
|
// typeVariableAliases.add(CharOperation.toString(tref.getTypeName()));//tVarsInGenericType[i]); |
|
|
|
// } |
|
|
|
// } |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -274,12 +292,64 @@ public abstract class InterTypeDeclaration extends AjMethodDeclaration { |
|
|
|
return declaredSelector; |
|
|
|
} |
|
|
|
|
|
|
|
public void setOnType(TypeReference onType) { |
|
|
|
this.onType = onType; |
|
|
|
} |
|
|
|
|
|
|
|
public TypeReference getOnType() { |
|
|
|
return onType; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Create the list of aliases based on what was supplied as parameters for the ontype. |
|
|
|
* For example, if the declaration is 'List<N> SomeType<N>.foo' then the alias list |
|
|
|
* will simply contain 'N' and 'N' will mean 'the first type variable declared for |
|
|
|
* type SomeType' |
|
|
|
*/ |
|
|
|
public void determineTypeVariableAliases() { |
|
|
|
if (onType!=null && onType instanceof ParameterizedSingleTypeReference) { |
|
|
|
ParameterizedSingleTypeReference paramRef = (ParameterizedSingleTypeReference) onType; |
|
|
|
TypeReference[] rb = paramRef.typeArguments; |
|
|
|
typeVariableAliases = new ArrayList(); |
|
|
|
for (int i = 0; i < rb.length; i++) { |
|
|
|
typeVariableAliases.add(CharOperation.toString(rb[i].getTypeName())); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Called just before the compiler is going to start resolving elements of a declaration, this method |
|
|
|
* adds an intertypescope between the methodscope and classscope so that elements of the type targetted |
|
|
|
* by the ITD can be resolved. For example, if type variables are referred to in the ontype for the ITD, |
|
|
|
* they have to be resolved against the ontype, not the aspect containing the ITD. |
|
|
|
*/ |
|
|
|
public void ensureScopeSetup() { |
|
|
|
if (scopeSetup) return; // don't do it agai |
|
|
|
MethodScope scope = this.scope; |
|
|
|
|
|
|
|
TypeReference ot = onType; |
|
|
|
|
|
|
|
// Work out the real base type |
|
|
|
if (ot instanceof ParameterizedSingleTypeReference) { |
|
|
|
ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) ot; |
|
|
|
long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd; |
|
|
|
ot = new SingleTypeReference(pref.token,pos); |
|
|
|
} |
|
|
|
|
|
|
|
// resolve it |
|
|
|
ReferenceBinding rb = (ReferenceBinding)ot.getTypeBindingPublic(scope.parent); |
|
|
|
|
|
|
|
// if resolution failed, give up - someone else is going to report an error |
|
|
|
if (rb instanceof ProblemReferenceBinding) return; |
|
|
|
|
|
|
|
ClassScope newParent = new InterTypeScope(scope.parent, rb, typeVariableAliases); |
|
|
|
// FIXME asc verify the choice of lines here... |
|
|
|
// Two versions of this next line. |
|
|
|
// First one tricks the JDT variable processing code so that it won't complain if |
|
|
|
// you refer to a type variable from a static ITD - it *is* a problem and it *will* be caught, but later and |
|
|
|
// by the AJDT code so we can put out a much nicer message. |
|
|
|
scope.isStatic = (typeVariableAliases!=null?false:Modifier.isStatic(declaredModifiers)); |
|
|
|
// this is the original version in case tricking the JDT causes grief (if you reinstate this variant, you |
|
|
|
// will need to change the expected messages output for some of the generic ITD tests) |
|
|
|
// scope.isStatic = Modifier.isStatic(declaredModifiers); |
|
|
|
scope.parent = newParent; |
|
|
|
scopeSetup = true; |
|
|
|
} |
|
|
|
} |