@@ -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, |
@@ -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 |
@@ -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()); |
@@ -14,8 +14,10 @@ | |||
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, |
@@ -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; |
@@ -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); | |||
} | |||
} |
@@ -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); |