World world = struct.enclosingType.getWorld();
NameValuePair declareMixinPatternNameValuePair = getAnnotationElement(declareMixinAnnotation, VALUE);
// declareMixinPattern could be of the form "Bar*" or "A || B" or "Foo+"
String declareMixinPattern = declareMixinPatternNameValuePair.getValue().stringifyValue();
TypePattern targetTypePattern = parseTypePattern(declareMixinPattern, struct);
// Return value of the annotated method is the interface or class that the mixin delegate should have
ResolvedType methodReturnType = UnresolvedType.forSignature(annotatedMethod.getReturnType().getSignature()).resolve(world);
if (methodReturnType.isPrimitiveType()) {
reportError(getMethodForMessage(struct) + ": factory methods for a mixin cannot return void or a primitive type",
struct);
return false;
}
if (annotatedMethod.getArgumentTypes().length > 1) {
reportError(getMethodForMessage(struct) + ": factory methods for a mixin can take a maximum of one parameter", struct);
return false;
}
// The set of interfaces to be mixed in is either:
// supplied as a list in the 'Class[] interfaces' value in the annotation value
// supplied as just the interface return value of the annotated method
// supplied as just the class return value of the annotated method
NameValuePair interfaceListSpecified = getAnnotationElement(declareMixinAnnotation, "interfaces");
List<TypePattern> newParents = new ArrayList<TypePattern>(1);
List<ResolvedType> newInterfaceTypes = new ArrayList<ResolvedType>(1);
if (interfaceListSpecified != null) {
ArrayElementValue arrayOfInterfaceTypes = (ArrayElementValue) interfaceListSpecified.getValue();
int numberOfTypes = arrayOfInterfaceTypes.getElementValuesArraySize();
ElementValue[] theTypes = arrayOfInterfaceTypes.getElementValuesArray();
for (int i = 0; i < numberOfTypes; i++) {
ClassElementValue interfaceType = (ClassElementValue) theTypes[i];
// Check: needs to be resolvable
// TODO crappy replace required
ResolvedType ajInterfaceType = UnresolvedType.forSignature(interfaceType.getClassString().replace("/", "."))
.resolve(world);
if (ajInterfaceType.isMissing() || !ajInterfaceType.isInterface()) {
reportError(
"Types listed in the 'interfaces' DeclareMixin annotation value must be valid interfaces. This is invalid: "
+ ajInterfaceType.getName(), struct); // TODO better error location, use the method position
return false;
}
if (!ajInterfaceType.isAssignableFrom(methodReturnType)) {
reportError(getMethodForMessage(struct) + ": factory method does not return something that implements '"
+ ajInterfaceType.getName() + "'", struct);
return false;
}
newInterfaceTypes.add(ajInterfaceType);
// Checking that it is a superinterface of the methods return value is done at weave time
TypePattern newParent = parseTypePattern(ajInterfaceType.getName(), struct);
newParents.add(newParent);
}
} else {
if (methodReturnType.isClass()) {
reportError(
getMethodForMessage(struct)
+ ": factory methods for a mixin must either return an interface type or specify interfaces in the annotation and return a class",
struct);
return false;
}
// Use the method return type: this might be a class or an interface
TypePattern newParent = parseTypePattern(methodReturnType.getName(), struct);
newInterfaceTypes.add(methodReturnType);
newParents.add(newParent);
}
if (newParents.size() == 0) {
// Warning: did they foolishly put @DeclareMixin(value="Bar+",interfaces={})