protected UnresolvedType returnType;
protected UnresolvedType[] parameterTypes;
private final String erasedSignature; // eg. (Ljava/util/Set;V)Ljava/lang/String;
- private String paramSignature; // eg. (Ljava/util/Set<Ljava/lang/String;>;V) // no return type
+ private String paramSignature; // eg. (Ljava/util/Set<Ljava/lang/String;>;V) // no return type
// OPTIMIZE move out of the member!
private boolean reportedCantFindDeclaringType = false;
private JoinPointSignatureIterator joinPointSignatures = null;
/**
- * Construct a MemberImpl using an erased signature for the parameters and return type (member method/ctor) or type (member field)
+ * Construct a MemberImpl using an erased signature for the parameters and return type (member method/ctor) or type (member
+ * field)
*/
public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name, String erasedSignature) {
this.kind = kind;
}
/**
- * Construct a MemberImpl using real type information for the parameters and return type (member method/ctor) or type (member field)
+ * Construct a MemberImpl using real type information for the parameters and return type (member method/ctor) or type (member
+ * field)
*/
public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
UnresolvedType[] parameterTypes) {
this.erasedSignature = returnType.getErasureSignature();
} else {
this.erasedSignature = typesToSignature(returnType, parameterTypes, true);
-
+
// Check parameter recovery by collapsing types to the string then rebuilding them from that
// this will check we are capable of having WeakRefs to the parameter types
-// String nonErasedSignature = getParameterSignature()+getReturnType().getSignature();
-// Object[] returnAndParams = signatureToTypes(nonErasedSignature);
-// UnresolvedType[] recoveredParams = (UnresolvedType[]) returnAndParams[1];
-// for (int jj=0;jj<parameterTypes.length;jj++) {
-// if (!parameterTypes[jj].getSignature().equals(recoveredParams[jj].getSignature())) {
-// throw new RuntimeException(parameterTypes[jj].getSignature()+" != "+recoveredParams[jj].getSignature()+" "+paramSignature);
-// }
-// }
+ // String nonErasedSignature = getParameterSignature()+getReturnType().getSignature();
+ // Object[] returnAndParams = signatureToTypes(nonErasedSignature);
+ // UnresolvedType[] recoveredParams = (UnresolvedType[]) returnAndParams[1];
+ // for (int jj=0;jj<parameterTypes.length;jj++) {
+ // if (!parameterTypes[jj].getSignature().equals(recoveredParams[jj].getSignature())) {
+ // throw new
+ // RuntimeException(parameterTypes[jj].getSignature()+" != "+recoveredParams[jj].getSignature()+" "+paramSignature);
+ // }
+ // }
}
-
+
}
public ResolvedMember resolve(World world) {
// ---- utility methods
/**
- * Build a signature based on the return type and parameter types. For example: "(Ljava/util/Set<Ljava/lang/String;>;)V"
- * or "(Ljava/util/Set;)V". The latter form shows what happens when the generics are erased
+ * Build a signature based on the return type and parameter types. For example: "(Ljava/util/Set<Ljava/lang/String;>;)V" or
+ * "(Ljava/util/Set;)V". The latter form shows what happens when the generics are erased
*/
public static String typesToSignature(UnresolvedType returnType, UnresolvedType[] paramTypes, boolean eraseGenerics) {
StringBuilder buf = new StringBuilder();
buf.append("(");
- for (UnresolvedType paramType: paramTypes) {
+ for (UnresolvedType paramType : paramTypes) {
if (eraseGenerics && (paramType.isParameterizedType() || paramType.isTypeVariableReference())) {
- buf.append(paramType.getErasureSignature());
+ buf.append(paramType.getErasureSignature());
} else {
- buf.append(paramType.getSignature());
+ buf.append(paramType.getSignature());
}
}
buf.append(")");
if (eraseGenerics && (returnType.isParameterizedType() || returnType.isTypeVariableReference())) {
- buf.append(returnType.getErasureSignature());
+ buf.append(returnType.getErasureSignature());
} else {
buf.append(returnType.getSignature());
}
} else if (c == 'T') { // assumed 'reference' to a type
// variable, so just "Tname;"
int nextSemicolon = sig.indexOf(';', start);
- String nextbit = sig.substring(start, nextSemicolon+1);
+ String nextbit = sig.substring(start, nextSemicolon + 1);
l.add(UnresolvedType.forSignature(nextbit));
i = nextSemicolon + 1;
} else {
public static MemberImpl method(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
return new MemberImpl(
// ??? this calls <clinit> a method
- name.equals("<init>") ? CONSTRUCTOR : METHOD, declTy, mods, rTy, name, paramTys);
+ name.equals("<init>") ? CONSTRUCTOR : METHOD, declTy, mods, rTy, name, paramTys);
}
private static Member pointcut(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
}
@Override
- public boolean equals(Object other) {
+ public final boolean equals(Object other) {
if (!(other instanceof Member)) {
return false;
}
.equals(o.getDeclaringType()));
}
+ /**
+ * @return true if this member equals the one supplied in every respect other than the declaring type
+ */
+ public final boolean equalsApartFromDeclaringType(Object other) {
+ if (!(other instanceof Member)) {
+ return false;
+ }
+ Member o = (Member) other;
+ return (getKind() == o.getKind() && getName().equals(o.getName()) && getSignature().equals(o.getSignature()));
+ }
+
/**
* Equality is checked based on the underlying signature, so the hash code of a member is based on its kind, name, signature,
* and declaring type. The algorithm for this was taken from page 38 of effective java.
// System.err.println(" compare: " + c);
if (c < 0) {
// the existing munger dominates the new munger
- checkLegalOverride(munger.getSignature(), existingMunger.getSignature());
+ checkLegalOverride(munger.getSignature(), existingMunger.getSignature(), 0x11, null);
return;
} else if (c > 0) {
// the new munger dominates the existing one
- checkLegalOverride(existingMunger.getSignature(), munger.getSignature());
+ checkLegalOverride(existingMunger.getSignature(), munger.getSignature(), 0x11, null);
i.remove();
break;
} else {
// System.err.println(" c: " + c);
if (c < 0) {
// existingMember dominates munger
- checkLegalOverride(typeTransformerSignature, existingMember);
+ checkLegalOverride(typeTransformerSignature, existingMember, 0x10, typeTransformer.getAspectType());
return true;
} else if (c > 0) {
// munger dominates existingMember
- checkLegalOverride(existingMember, typeTransformerSignature);
+ checkLegalOverride(existingMember, typeTransformerSignature, 0x01, typeTransformer.getAspectType());
// interTypeMungers.add(munger);
// ??? might need list of these overridden abstracts
continue;
}
/**
+ * @param transformerPosition which parameter is the type transformer (0x10 for first, 0x01 for second, 0x11 for both, 0x00 for
+ * neither)
+ * @param aspectType the declaring type of aspect defining the *first* type transformer
* @return true if the override is legal note: calling showMessage with two locations issues TWO messages, not ONE message with
* an additional source location.
*/
- public boolean checkLegalOverride(ResolvedMember parent, ResolvedMember child) {
+ public boolean checkLegalOverride(ResolvedMember parent, ResolvedMember child, int transformerPosition, ResolvedType aspectType) {
// System.err.println("check: " + child.getDeclaringType() +
// " overrides " + parent.getDeclaringType());
if (Modifier.isFinal(parent.getModifiers())) {
+ // If the ITD matching is occurring due to pulling in a BinaryTypeBinding then this check can incorrectly
+ // signal an error because the ITD transformer being examined here will exactly match the member it added
+ // during the first round of compilation. This situation can only occur if the ITD is on an interface whilst
+ // the class is the top most implementor. If the ITD is on the same type that received it during compilation,
+ // this method won't be called as the previous check for precedence level will return 0.
+
+ if (transformerPosition == 0x10 && aspectType != null) {
+ ResolvedType nonItdDeclaringType = child.getDeclaringType().resolve(world);
+ WeaverStateInfo wsi = nonItdDeclaringType.getWeaverState();
+ if (wsi != null) {
+ List<ConcreteTypeMunger> transformersOnThisType = wsi.getTypeMungers(nonItdDeclaringType);
+ if (transformersOnThisType != null) {
+ for (ConcreteTypeMunger transformer : transformersOnThisType) {
+ // relatively crude check - is the ITD
+ // for the same as the existingmember
+ // and does it come
+ // from the same aspect
+ if (transformer.aspectType.equals(aspectType)) {
+ if (parent.equalsApartFromDeclaringType(transformer.getSignature())) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
world.showMessage(Message.ERROR, WeaverMessages.format(WeaverMessages.CANT_OVERRIDE_FINAL_MEMBER, parent), child
.getSourceLocation(), null);
return false;
}
if (conflictingSignature(existing, toAdd)) {
if (isOverriding) {
- checkLegalOverride(existing, toAdd);
+ checkLegalOverride(existing, toAdd, 0x00, null);
j.remove();
} else {
getWorld().showMessage(