Browse Source

genericitds: An ITD now records the set of aliases used for type variables on a target type, and has the ability to modify the scope hierarchy for some member earlier than in resolve (required when using tvar references in ITD ontypes)

tags/V1_5_0M3
aclement 19 years ago
parent
commit
84cc03d325

+ 126
- 56
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeDeclaration.java View File

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

Loading…
Cancel
Save