diff options
author | aclement <aclement> | 2005-08-22 16:53:16 +0000 |
---|---|---|
committer | aclement <aclement> | 2005-08-22 16:53:16 +0000 |
commit | 84cc03d325e7662f1bfe6381a060cf36a829388b (patch) | |
tree | 1dc577fa9b1039ddbbaa87292d2aeb20543e0377 /org.aspectj.ajdt.core | |
parent | e4714fa267754554f6788c434cea03fb748d5a65 (diff) | |
download | aspectj-84cc03d325e7662f1bfe6381a060cf36a829388b.tar.gz aspectj-84cc03d325e7662f1bfe6381a060cf36a829388b.zip |
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)
Diffstat (limited to 'org.aspectj.ajdt.core')
-rw-r--r-- | org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeDeclaration.java | 182 |
1 files changed, 126 insertions, 56 deletions
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeDeclaration.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeDeclaration.java index b8eeb4a85..f48c1cc24 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeDeclaration.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeDeclaration.java @@ -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; + } } |