]> source.dussan.org Git - aspectj.git/commitdiff
genericitds: An ITD now records the set of aliases used for type variables on a targe...
authoraclement <aclement>
Mon, 22 Aug 2005 16:53:16 +0000 (16:53 +0000)
committeraclement <aclement>
Mon, 22 Aug 2005 16:53:16 +0000 (16:53 +0000)
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeDeclaration.java

index b8eeb4a855d90e2aea11fdd04fad674d723e2727..f48c1cc246e5c74b371db917302d548e8b9c2de5 100644 (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;
+       }
 }