Browse Source

390269: fix for multiple bridge candidates in hierarchy

tags/V1_7_2
Andy Clement 11 years ago
parent
commit
0bbb4f252a
1 changed files with 43 additions and 54 deletions
  1. 43
    54
      weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java

+ 43
- 54
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java View File



import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
/** /**
* Create a single bridge method called 'theBridgeMethod' that bridges to 'whatToBridgeTo' * Create a single bridge method called 'theBridgeMethod' that bridges to 'whatToBridgeTo'
*/ */
private static void createBridgeMethod(BcelWorld world, LazyMethodGen whatToBridgeToMethodGen, LazyClassGen clazz,
ResolvedMember theBridgeMethod) {
private static void createBridgeMethod(BcelWorld world, LazyMethodGen whatToBridgeToMethodGen, LazyClassGen clazz, ResolvedMember theBridgeMethod) {
InstructionList body; InstructionList body;
InstructionFactory fact; InstructionFactory fact;
int pos = 0; int pos = 0;
// FIXASC refactor into ResolvedType or even ResolvedMember? // FIXASC refactor into ResolvedType or even ResolvedMember?
/** /**
* Check if a particular method is overriding another - refactored into this helper so it can be used from multiple places. * Check if a particular method is overriding another - refactored into this helper so it can be used from multiple places.
* @return method that is overriding if it
*/ */
private static ResolvedMember isOverriding(ResolvedType typeToCheck, ResolvedMember methodThatMightBeGettingOverridden, private static ResolvedMember isOverriding(ResolvedType typeToCheck, ResolvedMember methodThatMightBeGettingOverridden,
String mname, String mrettype, int mmods, boolean inSamePackage, UnresolvedType[] methodParamsArray) { String mname, String mrettype, int mmods, boolean inSamePackage, UnresolvedType[] methodParamsArray) {
* *
* @return the method being overridden or null if none is found * @return the method being overridden or null if none is found
*/ */
public static ResolvedMember checkForOverride(ResolvedType typeToCheck, String mname, String mparams, String mrettype,
int mmods, String mpkg, UnresolvedType[] methodParamsArray) {
public static void checkForOverride(ResolvedType typeToCheck, String mname, String mparams, String mrettype,
int mmods, String mpkg, UnresolvedType[] methodParamsArray, List<ResolvedMember> overriddenMethodsCollector) {


if (typeToCheck == null) { if (typeToCheck == null) {
return null;
return;
} }
if (typeToCheck instanceof MissingResolvedTypeWithKnownSignature) { if (typeToCheck instanceof MissingResolvedTypeWithKnownSignature) {
return null; // we just can't tell !
return; // we just can't tell !
} }


if (typeToCheck.getWorld().forDEBUG_bridgingCode) { if (typeToCheck.getWorld().forDEBUG_bridgingCode) {
System.err.println(" Bridging:checking for override of " + mname + " in " + typeToCheck); System.err.println(" Bridging:checking for override of " + mname + " in " + typeToCheck);
if (packageName == null) { if (packageName == null) {
packageName = ""; packageName = "";
} }
boolean inSamePackage = packageName.equals(mpkg); // used when looking
// at visibility
// rules
// used when looking at visibility rules
boolean inSamePackage = packageName.equals(mpkg);


ResolvedMember[] methods = typeToCheck.getDeclaredMethods(); ResolvedMember[] methods = typeToCheck.getDeclaredMethods();
for (int ii = 0; ii < methods.length; ii++) { for (int ii = 0; ii < methods.length; ii++) {
ResolvedMember isOverriding = isOverriding(typeToCheck, methodThatMightBeGettingOverridden, mname, mrettype, mmods, ResolvedMember isOverriding = isOverriding(typeToCheck, methodThatMightBeGettingOverridden, mname, mrettype, mmods,
inSamePackage, methodParamsArray); inSamePackage, methodParamsArray);
if (isOverriding != null) { if (isOverriding != null) {
return isOverriding;
overriddenMethodsCollector.add(isOverriding);
} }
} }
// was: List l = typeToCheck.getInterTypeMungers(); // was: List l = typeToCheck.getInterTypeMungers();
ResolvedMember isOverriding = isOverriding(typeToCheck, aMethod, mname, mrettype, mmods, inSamePackage, ResolvedMember isOverriding = isOverriding(typeToCheck, aMethod, mname, mrettype, mmods, inSamePackage,
methodParamsArray); methodParamsArray);
if (isOverriding != null) { if (isOverriding != null) {
return isOverriding;
overriddenMethodsCollector.add(isOverriding);
} }
} }
} }
} }


if (typeToCheck.equals(UnresolvedType.OBJECT)) { if (typeToCheck.equals(UnresolvedType.OBJECT)) {
return null;
return;
} }


ResolvedType superclass = typeToCheck.getSuperclass(); ResolvedType superclass = typeToCheck.getSuperclass();
ResolvedMember overriddenMethod = checkForOverride(superclass, mname, mparams, mrettype, mmods, mpkg, methodParamsArray);
if (overriddenMethod != null) {
return overriddenMethod;
}

checkForOverride(superclass, mname, mparams, mrettype, mmods, mpkg, methodParamsArray,overriddenMethodsCollector);
ResolvedType[] interfaces = typeToCheck.getDeclaredInterfaces(); ResolvedType[] interfaces = typeToCheck.getDeclaredInterfaces();
for (int i = 0; i < interfaces.length; i++) { for (int i = 0; i < interfaces.length; i++) {
ResolvedType anInterface = interfaces[i]; ResolvedType anInterface = interfaces[i];
overriddenMethod = checkForOverride(anInterface, mname, mparams, mrettype, mmods, mpkg, methodParamsArray);
if (overriddenMethod != null) {
return overriddenMethod;
}
checkForOverride(anInterface, mname, mparams, mrettype, mmods, mpkg, methodParamsArray,overriddenMethodsCollector);
} }
return null;
} }


/** /**
*/ */
public static boolean calculateAnyRequiredBridgeMethods(BcelWorld world, LazyClassGen clazz) { public static boolean calculateAnyRequiredBridgeMethods(BcelWorld world, LazyClassGen clazz) {
world.ensureAdvancedConfigurationProcessed(); world.ensureAdvancedConfigurationProcessed();
if (!world.isInJava5Mode()) { if (!world.isInJava5Mode()) {
return false; // just double check... the caller should have already return false; // just double check... the caller should have already
} }
// verified this
if (clazz.isInterface()) { if (clazz.isInterface()) {
return false; // dont bother if we're an interface
return false; // dont bother if we are an interface
} }
boolean didSomething = false; // set if we build any bridge methods boolean didSomething = false; // set if we build any bridge methods

// So what methods do we have right now in this class? // So what methods do we have right now in this class?
List<LazyMethodGen> methods = clazz.getMethodGens(); List<LazyMethodGen> methods = clazz.getMethodGens();


// Keep a set of all methods from this type - it'll help us to check if
// bridge methods
// Keep a set of all methods from this type - it'll help us to check if bridge methods
// have already been created, we don't want to do it twice! // have already been created, we don't want to do it twice!
Set<String> methodsSet = new HashSet<String>(); Set<String> methodsSet = new HashSet<String>();
for (int i = 0; i < methods.size(); i++) { for (int i = 0; i < methods.size(); i++) {
LazyMethodGen aMethod = methods.get(i); LazyMethodGen aMethod = methods.get(i);
methodsSet.add(aMethod.getName() + aMethod.getSignature()); // e.g.
// "foo(Ljava/lang/String;)V"
StringBuilder sb = new StringBuilder(aMethod.getName());
sb.append(aMethod.getSignature());
methodsSet.add(sb.toString()); // e.g. "foo(Ljava/lang/String;)V"
} }


// Now go through all the methods in this type // Now go through all the methods in this type
for (int i = 0; i < methods.size(); i++) { for (int i = 0; i < methods.size(); i++) {

// This is the local method that we *might* have to bridge to // This is the local method that we *might* have to bridge to
LazyMethodGen bridgeToCandidate = methods.get(i); LazyMethodGen bridgeToCandidate = methods.get(i);
if (bridgeToCandidate.isBridgeMethod()) { if (bridgeToCandidate.isBridgeMethod()) {
} }


if (world.forDEBUG_bridgingCode) { if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging: Determining if we have to bridge to " + clazz.getName() + "." + name + ""
+ bridgeToCandidate.getSignature());
System.err.println("Bridging: Determining if we have to bridge to " + clazz.getName() + "." + name + "" + bridgeToCandidate.getSignature());
} }


// Let's take a look at the superclass // Let's take a look at the superclass
} }
String pkgName = clazz.getPackageName(); String pkgName = clazz.getPackageName();
UnresolvedType[] bm = BcelWorld.fromBcel(bridgeToCandidate.getArgumentTypes()); UnresolvedType[] bm = BcelWorld.fromBcel(bridgeToCandidate.getArgumentTypes());
ResolvedMember overriddenMethod = checkForOverride(theSuperclass, name, psig, rsig, bridgeToCandidate.getAccessFlags(),
pkgName, bm);
if (overriddenMethod != null) {
String key = new StringBuffer().append(overriddenMethod.getName()).append(overriddenMethod.getSignatureErased())
.toString(); // pr237419
boolean alreadyHaveABridgeMethod = methodsSet.contains(key);
if (!alreadyHaveABridgeMethod) {
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging:bridging to '" + overriddenMethod + "'");
List<ResolvedMember> overriddenMethodsCollector = new ArrayList<ResolvedMember>();
checkForOverride(theSuperclass, name, psig, rsig, bridgeToCandidate.getAccessFlags(), pkgName, bm, overriddenMethodsCollector);
if (overriddenMethodsCollector.size() != 0) {
for (ResolvedMember overriddenMethod: overriddenMethodsCollector) {
String key = new StringBuilder(overriddenMethod.getName()).append(overriddenMethod.getSignatureErased()).toString(); // pr237419
boolean alreadyHaveABridgeMethod = methodsSet.contains(key);
if (!alreadyHaveABridgeMethod) {
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging:bridging to '" + overriddenMethod + "'");
}
createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
methodsSet.add(key);
didSomething = true;
} }
createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
methodsSet.add(key);
didSomething = true;
continue; // look at the next method
} }
} }


System.err.println("Bridging:checking superinterface " + interfaces[j]); System.err.println("Bridging:checking superinterface " + interfaces[j]);
} }
ResolvedType interfaceType = world.resolve(interfaces[j]); ResolvedType interfaceType = world.resolve(interfaces[j]);
overriddenMethod = checkForOverride(interfaceType, name, psig, rsig, bridgeToCandidate.getAccessFlags(),
clazz.getPackageName(), bm);
if (overriddenMethod != null) {
String key = new StringBuffer().append(overriddenMethod.getName())
.append(overriddenMethod.getSignatureErased()).toString(); // pr
// 237419
overriddenMethodsCollector.clear();
checkForOverride(interfaceType, name, psig, rsig, bridgeToCandidate.getAccessFlags(),
clazz.getPackageName(), bm, overriddenMethodsCollector);
for (ResolvedMember overriddenMethod: overriddenMethodsCollector) {
String key = new StringBuffer().append(overriddenMethod.getName()).append(overriddenMethod.getSignatureErased()).toString(); // pr237419
boolean alreadyHaveABridgeMethod = methodsSet.contains(key); boolean alreadyHaveABridgeMethod = methodsSet.contains(key);
if (!alreadyHaveABridgeMethod) { if (!alreadyHaveABridgeMethod) {
createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod); createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
if (world.forDEBUG_bridgingCode) { if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging:bridging to " + overriddenMethod); System.err.println("Bridging:bridging to " + overriddenMethod);
} }
continue; // look at the next method
} }
} }
} }
return didSomething; return didSomething;
} }


// **************************** end of bridge method creation code
// *****************
// **************************** end of bridge method creation code *****************


/** /**
* Weave any declare @method/@ctor statements into the members of the supplied class * Weave any declare @method/@ctor statements into the members of the supplied class

Loading…
Cancel
Save