From d4db815bd941b1a07c8c961613672480afbce8e4 Mon Sep 17 00:00:00 2001 From: aclement Date: Fri, 6 Mar 2009 18:57:45 +0000 Subject: [PATCH] declaremixin --- .../aspectj/weaver/bcel/AtAjAttributes.java | 151 +++--------------- 1 file changed, 22 insertions(+), 129 deletions(-) diff --git a/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java b/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java index 3743afa33..12ee8ef3b 100644 --- a/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java +++ b/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java @@ -899,7 +899,7 @@ public class AtAjAttributes { ElementNameValuePairGen interfaceListSpecified = getAnnotationElement(declareMixinAnnotation, "interfaces"); List newParents = new ArrayList(1); - List newParentTypes = new ArrayList(1); + List newInterfaceTypes = new ArrayList(1); if (interfaceListSpecified != null) { ArrayElementValueGen arrayOfInterfaceTypes = (ArrayElementValueGen) interfaceListSpecified.getValue(); int numberOfTypes = arrayOfInterfaceTypes.getElementValuesArraySize(); @@ -910,21 +910,33 @@ public class AtAjAttributes { // TODO crappy replace required ResolvedType ajInterfaceType = UnresolvedType.forSignature(interfaceType.getClassString().replace("/", ".")) .resolve(world); - newParentTypes.add(ajInterfaceType); 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); - newParentTypes.add(methodReturnType); + newInterfaceTypes.add(methodReturnType); newParents.add(newParent); } if (newParents.size() == 0) { @@ -932,116 +944,25 @@ public class AtAjAttributes { // TODO output warning return false; } - // TODO DECLAREMIXIN set the location more accurately than - // this + + // Create the declare parents that will add the interfaces to matching targets FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - // first add the declare implements like // how do we mark this as a decp due to decmixin? DeclareParents dp = new DeclareParentsMixin(targetTypePattern, newParents); - dp.resolve(binding); // resolves the parent and child parts - // of the decp - - // resolve this so that we can use it for the - // MethodDelegateMungers below. - // eg. '@Coloured *' will change from a WildTypePattern to - // an 'AnyWithAnnotationTypePattern' after this - // resolution - targetTypePattern = dp.getChild();// targetTypePattern.resolveBindings(binding, Bindings.NONE, false, false); - // TODO kick ISourceLocation sl = - // struct.bField.getSourceLocation(); ?? - // dp.setLocation(dp.getDeclaringType().getSourceContext(), - // dp.getDeclaringType().getSourceLocation().getOffset(), - // dp.getDeclaringType().getSourceLocation().getOffset()); + dp.resolve(binding); + targetTypePattern = dp.getChild(); + dp.setLocation(struct.context, -1, -1); // not ideal... struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp)); // The factory method for building the implementation is the // one attached to the annotation: Method implementationFactory = struct.method; - // do we have a defaultImpl=xxx.class (ie implementation) - // String defaultImplClassName = null; - // ElementNameValuePairGen defaultImplNVP = - // getAnnotationElement(declareMixinAnnotation, - // "defaultImpl"); - // if (defaultImplNVP != null) { - // ClassElementValueGen defaultImpl = (ClassElementValueGen) - // defaultImplNVP.getValue(); - // defaultImplClassName = - // UnresolvedType.forSignature(defaultImpl.getClassString()).getName(); - // if - // (defaultImplClassName.equals("org.aspectj.lang.annotation.DeclareParents")) - // { - // defaultImplClassName = null; - // } else { - // // check public no arg ctor - // ResolvedType impl = - // struct.enclosingType.getWorld().resolve(defaultImplClassName, - // false); - // ResolvedMember[] mm = impl.getDeclaredMethods(); - // int implModifiers = impl.getModifiers(); - // boolean defaultVisibilityImpl = - // !(Modifier.isPrivate(implModifiers) - // || Modifier.isProtected(implModifiers) || - // Modifier.isPublic(implModifiers)); - // boolean hasNoCtorOrANoArgOne = true; - // ResolvedMember foundOneOfIncorrectVisibility = null; - // for (int i = 0; i < mm.length; i++) { - // ResolvedMember resolvedMember = mm[i]; - // if (resolvedMember.getName().equals("")) { - // hasNoCtorOrANoArgOne = false; - // - // if (resolvedMember.getParameterTypes().length == 0) { - // if (defaultVisibilityImpl) { // default visibility - // implementation - // if (resolvedMember.isPublic() || - // resolvedMember.isDefault()) { - // hasNoCtorOrANoArgOne = true; - // } else { - // foundOneOfIncorrectVisibility = resolvedMember; - // } - // } else if (Modifier.isPublic(implModifiers)) { // public - // implementation - // if (resolvedMember.isPublic()) { - // hasNoCtorOrANoArgOne = true; - // } else { - // foundOneOfIncorrectVisibility = resolvedMember; - // } - // } - // } - // } - // if (hasNoCtorOrANoArgOne) { - // break; - // } - // } - // if (!hasNoCtorOrANoArgOne) { - // if (foundOneOfIncorrectVisibility != null) { - // reportError( - // "@DeclareParents: defaultImpl=\"" - // + defaultImplClassName - // + - // "\" has a no argument constructor, but it is of incorrect visibility. It must be at least as visible as the type.", - // struct); - // } else { - // reportError("@DeclareParents: defaultImpl=\"" + - // defaultImplClassName - // + "\" has no public no-arg constructor", struct); - // } - // } - // if (!methodType.isAssignableFrom(impl)) { - // reportError("@DeclareParents: defaultImpl=\"" + - // defaultImplClassName - // + "\" does not implement the interface '" + - // methodType.toString() + "'", struct); - // } - // } - // - // } - // then iterate on field interface hierarchy (not object) boolean hasAtLeastOneMethod = false; - for (Iterator iterator = newParentTypes.iterator(); iterator.hasNext();) { + for (Iterator iterator = newInterfaceTypes.iterator(); iterator.hasNext();) { ResolvedType typeForDelegation = (ResolvedType) iterator.next(); // TODO check for overlapping interfaces. Eg. A implements I, I extends J - if they specify interfaces={I,J} we dont // want to do any methods twice @@ -1050,30 +971,7 @@ public class AtAjAttributes { for (int i = 0; i < methods.length; i++) { ResolvedMember method = methods[i]; if (method.isAbstract()) { - // moved to be detected at weave time if the target - // doesnt implement the methods - // if (defaultImplClassName == null) { - // // non marker interface with no default impl - // provided - // reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", - // struct); - // return false; - // } hasAtLeastOneMethod = true; - // What we are saying here: - // We have this method 'method' and we want to put a - // forwarding method into a type that matches - // typePattern that should delegate to the version - // of the method in 'defaultImplClassName' - - // Now the method may be from a supertype but the - // declaring type of the method we pass into the - // type - // munger is what is used to determine the type of - // the field that hosts the delegate instance. - // So here we create a modified method with an - // alternative declaring type so that we lookup - // the right field. See pr164016. MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, "", targetTypePattern, struct.method.getName(), struct.method.getSignature()); mdtm.setFieldType(methodReturnType); @@ -1082,17 +980,12 @@ public class AtAjAttributes { } } } - // successfull so far, we thus need a bcel type munger to - // have - // a field hosting the mixin in the target type + // if any method delegate was created then a field to hold the delegate instance must also be added if (hasAtLeastOneMethod) { ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, methodReturnType, struct.enclosingType); struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger(fieldHost, struct.enclosingType, targetTypePattern))); - } else { - return false; } - return true; } -- 2.39.5