]> source.dussan.org Git - aspectj.git/commitdiff
declaremixin
authoraclement <aclement>
Fri, 6 Mar 2009 18:57:45 +0000 (18:57 +0000)
committeraclement <aclement>
Fri, 6 Mar 2009 18:57:45 +0000 (18:57 +0000)
weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java

index 3743afa330683231818ba3eb80b31815f03e33fd..12ee8ef3b9a044f8a39be4506e05dd20800a48bc 100644 (file)
@@ -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("<init>")) {
-               // 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;
        }