]> source.dussan.org Git - aspectj.git/commitdiff
fix for pr87530, final modifier on interface itdm
authoracolyer <acolyer>
Mon, 5 Sep 2005 14:10:13 +0000 (14:10 +0000)
committeracolyer <acolyer>
Mon, 5 Sep 2005 14:10:13 +0000 (14:10 +0000)
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeMethodDeclaration.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/InterTypeMemberFinder.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/InterTypeMethodBinding.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/problem/AjProblemReporter.java
org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip
org.eclipse.jdt.core/jdtcore-for-aspectj.jar
weaver/src/org/aspectj/weaver/ResolvedType.java

index a56f2a161b4d77c30e6e1f5924c7022cd4864915..666335db75e24c275ca8f6f69fafd782e4e239c3 100644 (file)
@@ -63,6 +63,10 @@ public class InterTypeMethodDeclaration extends InterTypeDeclaration {
        protected char[] getPrefix() {
                return (NameMangler.ITD_PREFIX + "interMethod$").toCharArray();
        }
+       
+       public boolean isFinal() {
+               return  (declaredModifiers & AccFinal) != 0;            
+       }
 
        public void analyseCode(
                ClassScope currentScope,
index 4bd5cd7be22ed69b704e590bf189b0ccf49da162..32dd4c188fc06eccd6af16fd78630f924d31796e 100644 (file)
@@ -384,7 +384,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                        for (Iterator i = mungers.iterator(); i.hasNext(); ) {
                                ConcreteTypeMunger m = (ConcreteTypeMunger)i.next();
                                EclipseTypeMunger munger = factory.makeEclipseTypeMunger(m);
-                               if (munger.munge(sourceType)) {
+                               if (munger.munge(sourceType,onType)) {
                                        if (onType.isInterface() &&
                                                munger.getMunger().needsAccessToTopmostImplementor())
                                        {
@@ -509,7 +509,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                for (Iterator i = onType.getInterTypeMungers().iterator(); i.hasNext();) {
                        EclipseTypeMunger munger = (EclipseTypeMunger) i.next();
                        //System.out.println("applying: " + munger + " to " + new String(sourceType.sourceName));
-                       munger.munge(sourceType);
+                       munger.munge(sourceType,onType);
                }
                
                // Call if you would like to do source weaving of declare @method/@constructor 
index 038d92d22a1dfa6eef7349c1c72cb4d710bc2233..e499f2df562af92dd97d19197974704dba93c7d1 100644 (file)
@@ -17,6 +17,7 @@ import java.lang.reflect.Modifier;
 
 import org.aspectj.bridge.ISourceLocation;
 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.env.IConstants;
 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
@@ -24,6 +25,7 @@ import org.aspectj.weaver.ConcreteTypeMunger;
 import org.aspectj.weaver.NewConstructorTypeMunger;
 import org.aspectj.weaver.NewFieldTypeMunger;
 import org.aspectj.weaver.NewMethodTypeMunger;
+import org.aspectj.weaver.ResolvedMember;
 import org.aspectj.weaver.ResolvedType;
 import org.aspectj.weaver.ResolvedTypeMunger;
 
@@ -70,17 +72,29 @@ public class EclipseTypeMunger extends ConcreteTypeMunger {
         * Modifies signatures of a TypeBinding through its ClassScope,
         * i.e. adds Method|FieldBindings, plays with inheritance, ...
         */
-       public boolean munge(SourceTypeBinding sourceType) {
-               ResolvedType rt = world.fromEclipse(sourceType);
+       public boolean munge(SourceTypeBinding sourceType, ResolvedType onType) {
+               ResolvedType rt = onType;
                if (rt.isRawType() || rt.isParameterizedType()) rt = rt.getGenericType();
-               if (!rt.equals(targetTypeX)) return false; //??? move this test elsewhere
+               boolean isExactTargetType = rt.equals(targetTypeX);
+               if (!isExactTargetType) {
+                       // might be the topmost implementor of an interface we care about
+                       if (munger.getKind() != ResolvedTypeMunger.Method) return false;
+                       if (onType.isInterface()) return false;
+                       if (!munger.needsAccessToTopmostImplementor()) return false;
+                       // so we do need access, and this type could be it...
+                       if (!onType.isTopmostImplementor(targetTypeX)) return false;
+                       // we are the topmost implementor of an interface type that needs munging
+                       // but we only care about public methods here (we only do this at all to 
+                       // drive the JDT MethodVerifier correctly)
+                       if (!Modifier.isPublic(munger.getSignature().getModifiers())) return false;
+               }
                //System.out.println("munging: " + sourceType);
 //             System.out.println("match: " + world.fromEclipse(sourceType) +
 //                             " with " + targetTypeX);
                if (munger.getKind() == ResolvedTypeMunger.Field) {
                        mungeNewField(sourceType, (NewFieldTypeMunger)munger);
                } else if (munger.getKind() == ResolvedTypeMunger.Method) {
-                       mungeNewMethod(sourceType, (NewMethodTypeMunger)munger);
+                       return mungeNewMethod(sourceType, onType, (NewMethodTypeMunger)munger, isExactTargetType);
                } else if (munger.getKind() == ResolvedTypeMunger.Constructor) {
                        mungeNewConstructor(sourceType, (NewConstructorTypeMunger)munger);
                } else {
@@ -90,18 +104,39 @@ public class EclipseTypeMunger extends ConcreteTypeMunger {
        }
        
 
-       private void mungeNewMethod(SourceTypeBinding sourceType, NewMethodTypeMunger munger) {
-//             if (shouldTreatAsPublic()) {
-//                     MethodBinding binding = world.makeMethodBinding(munger.getSignature());
-//                     findOrCreateInterTypeMemberFinder(classScope).addInterTypeMethod(binding);
-//                     //classScope.referenceContext.binding.addMethod(binding);
-//             } else {
-                       InterTypeMethodBinding binding =
-                               new InterTypeMethodBinding(world, munger.getSignature(), aspectType, sourceMethod);
-                       findOrCreateInterTypeMemberFinder(sourceType).addInterTypeMethod(binding);
-//             }
+       private boolean mungeNewMethod(SourceTypeBinding sourceType, ResolvedType onType, NewMethodTypeMunger munger, boolean isExactTargetType) {
+               InterTypeMethodBinding binding =
+                       new InterTypeMethodBinding(world, munger.getSignature(), aspectType, sourceMethod);
 
+               if (!isExactTargetType) {
+                       // we're munging an interface ITD onto a topmost implementor
+                       ResolvedMember existingMember = onType.lookupMemberIncludingITDsOnInterfaces(getSignature()); 
+                       if (existingMember != null) {
+                               // already have an implementation, so don't do anything
+                               if (onType == existingMember.getDeclaringType() && Modifier.isFinal(munger.getSignature().getModifiers())) {
+                                       // final modifier on default implementation is taken to mean that
+                                       // no-one else can provide an implementation
+                                       MethodBinding offendingBinding = sourceType.getExactMethod(binding.selector, binding.parameters, sourceType.scope.compilationUnitScope());
+                                       sourceType.scope.problemReporter().finalMethodCannotBeOverridden(offendingBinding, binding);
+                               }
+                               // so that we find methods from our superinterfaces later on...
+                               findOrCreateInterTypeMemberFinder(sourceType);
+                               return false;
+                       } 
+               }
+               
+               // retain *only* the visibility modifiers and abstract when putting methods on an interface...
+               if (sourceType.isInterface()) {
+                       boolean isAbstract = (binding.modifiers & IConstants.AccAbstract) != 0;
+                       binding.modifiers = (binding.modifiers & (IConstants.AccPublic | IConstants.AccProtected | IConstants.AccPrivate));
+                       if (isAbstract) binding.modifiers |= IConstants.AccAbstract;
+               }
+               
+               findOrCreateInterTypeMemberFinder(sourceType).addInterTypeMethod(binding);
+               return true;
        }
+       
+       
        private void mungeNewConstructor(SourceTypeBinding sourceType, NewConstructorTypeMunger munger) {               
                if (shouldTreatAsPublic()) {
                        MethodBinding binding = world.makeMethodBinding(munger.getSignature());
index db7e8131e98e387ed37c1fd308262fe9c0a28919..e69e40978547dc3398a207534f07eb5f84d61a24 100644 (file)
 
 package org.aspectj.ajdt.internal.compiler.lookup;
 
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 
 import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
@@ -242,9 +244,11 @@ public class InterTypeMemberFinder implements IMemberFinder {
 //             return m2.declaringClass;
 //     }
 
+       // find all of my methods, including ITDs
+       // PLUS: any public ITDs made on interfaces that I implement
        public MethodBinding[] methods(SourceTypeBinding sourceTypeBinding) {
                MethodBinding[] orig = sourceTypeBinding.methods();
-               if (interTypeMethods.isEmpty()) return orig;
+//             if (interTypeMethods.isEmpty()) return orig;
                
                List ret = new ArrayList(Arrays.asList(orig));
                for (int i=0, len=interTypeMethods.size(); i < len; i++) {
@@ -252,10 +256,34 @@ public class InterTypeMemberFinder implements IMemberFinder {
                        ret.add(method);
                }
                
+               ReferenceBinding [] interfaces = sourceTypeBinding.superInterfaces();
+               for (int i = 0; i < interfaces.length; i++) {
+                       if (interfaces[i] instanceof SourceTypeBinding) {
+                               SourceTypeBinding intSTB = (SourceTypeBinding) interfaces[i];
+                               addPublicITDSFrom(intSTB,ret);
+                       }
+               }
+               
                if (ret.isEmpty()) return SourceTypeBinding.NoMethods;
                return (MethodBinding[])ret.toArray(new MethodBinding[ret.size()]);     
        }
        
+       private void addPublicITDSFrom(SourceTypeBinding anInterface,List toAList) {
+               if (anInterface.memberFinder != null) {
+                       InterTypeMemberFinder finder = (InterTypeMemberFinder) anInterface.memberFinder;
+                       for (Iterator iter = finder.interTypeMethods.iterator(); iter.hasNext();) {
+                               MethodBinding aBinding = (MethodBinding) iter.next();
+                               if (Modifier.isPublic(aBinding.modifiers)) {
+                                       toAList.add(aBinding);
+                               }
+                       }
+               }
+               ReferenceBinding superType = anInterface.superclass;
+               if (superType instanceof SourceTypeBinding && superType.isInterface()) {
+                       addPublicITDSFrom((SourceTypeBinding)superType,toAList);
+               }
+       }
+       
        //XXX conflicts
        public MethodBinding[] getMethods(
                SourceTypeBinding sourceTypeBinding,
index 290c9ee15e3a433cafa11eb8ede0793e9fdba7ff..658b6ef1384b73fe1f9d475a06479fdeda0a1d36 100644 (file)
@@ -17,6 +17,7 @@ import org.aspectj.weaver.AjcMemberMaker;
 import org.aspectj.weaver.Member;
 import org.aspectj.weaver.ResolvedMember;
 import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration;
 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -128,7 +129,11 @@ public class InterTypeMethodBinding extends MethodBinding {
                return false;
        }
 
-
+       public boolean isFinal() {
+               if (sourceMethod == null || !(sourceMethod instanceof InterTypeMethodDeclaration)) return super.isFinal();
+               return ((InterTypeMethodDeclaration)sourceMethod).isFinal();
+       }
+       
        public MethodBinding getAccessMethod(boolean staticReference) {
                if (staticReference) return postDispatchMethod;
                else return syntheticMethod;
index 34028b337975841213b5248afc365d16e316d6bd..421286af11f5a55e1682e4feb57c72d2354ced95 100644 (file)
@@ -412,4 +412,14 @@ public class AjProblemReporter extends ProblemReporter {
        if (!(methodDecl instanceof PointcutDeclaration))
                        super.unusedPrivateMethod(methodDecl);
     }
+
+    /**
+     * A side-effect of the way that we handle itds on default methods on top-most implementors
+     * of interfaces is that a class acquiring a final default ITD will erroneously report
+     * that it can't override its own member. This method detects that situation.
+     */
+    public void finalMethodCannotBeOverridden(MethodBinding currentMethod, MethodBinding inheritedMethod) {
+       if (currentMethod == inheritedMethod) return;
+       super.finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
+    }
 }
index c486d3bade398e04662645faa2da20fbf99f5344..2cb7b2bd3bc32a9dcdcb5b8286fa77c22d2ac337 100644 (file)
Binary files a/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip and b/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip differ
index e5c64c28a58b96c8d411d3c7a335c951227aa609..2c246f462011bbf6e701538f2b018641b93a6ebf 100644 (file)
Binary files a/org.eclipse.jdt.core/jdtcore-for-aspectj.jar and b/org.eclipse.jdt.core/jdtcore-for-aspectj.jar differ
index 0e8ba26c7c4939aa1df56f775a64c97e885c3152..73142c23bf6c2ac7526360335fbe8458299d6922 100644 (file)
@@ -905,6 +905,24 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl
      * Look up a member, takes into account any ITDs on this type.
      * return null if not found */
        public ResolvedMember lookupMemberNoSupers(Member member) {
+               ResolvedMember ret = lookupDirectlyDeclaredMemberNoSupers(member);
+               if (ret == null && interTypeMungers != null) {
+                       for (Iterator i = interTypeMungers.iterator(); i.hasNext();) {
+                               ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next();
+                               if (matches(tm.getSignature(), member)) {
+                                       return tm.getSignature();
+                               }
+                       }
+               }
+               return ret;
+       }
+       
+       /**
+        * as lookupMemberNoSupers, but does not include ITDs
+        * @param member
+        * @return
+        */
+       public ResolvedMember lookupDirectlyDeclaredMemberNoSupers(Member member) {
                ResolvedMember ret;
                if (member.getKind() == Member.FIELD) {
                        ret = lookupMember(member, getDeclaredFields());
@@ -912,11 +930,35 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl
                        // assert member.getKind() == Member.METHOD || member.getKind() == Member.CONSTRUCTOR
                        ret = lookupMember(member, getDeclaredMethods());
                }
-               if (ret == null && interTypeMungers != null) {
-                       for (Iterator i = interTypeMungers.iterator(); i.hasNext();) {
-                               ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next();
-                               if (matches(tm.getSignature(), member)) {
-                                       return tm.getSignature();
+               return ret;
+       }
+       
+       /**
+        * This lookup has specialized behaviour - a null result tells the
+        * EclipseTypeMunger that it should make a default implementation of a
+        * method on this type.
+        * @param member
+        * @return
+        */
+       public ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member) {
+               return lookupMemberIncludingITDsOnInterfaces(member, this);
+       }
+       
+       private ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member, ResolvedType onType) {
+               ResolvedMember ret = onType.lookupMemberNoSupers(member);
+               if (ret != null) {
+                       return ret;
+               } else {
+                       ResolvedType superType = onType.getSuperclass();
+                       if (superType != null) {
+                               ret = lookupMemberIncludingITDsOnInterfaces(member,superType);
+                       }
+                       if (ret == null) {
+                               // try interfaces then, but only ITDs now...
+                               ResolvedType[] superInterfaces = onType.getDeclaredInterfaces();
+                               for (int i = 0; i < superInterfaces.length; i++) {
+                                       ret = superInterfaces[i].lookupMethodInITDs(member);
+                                       if (ret != null) return ret;
                                }
                        }
                }
@@ -1256,6 +1298,9 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl
        public boolean checkLegalOverride(ResolvedMember parent, ResolvedMember child) {
                //System.err.println("check: " + child.getDeclaringType() + " overrides " + parent.getDeclaringType());
                if (Modifier.isFinal(parent.getModifiers())) {
+                       // XXX horrible test, if we're in eclipes, child.getSourceLocation will be
+                       // null, and this message will have already been issued.
+                       if (child.getSourceLocation() == null) return false;
                        world.showMessage(Message.ERROR,
                                        WeaverMessages.format(WeaverMessages.CANT_OVERRIDE_FINAL_MEMBER,parent),
                                        child.getSourceLocation(),null);