]> source.dussan.org Git - aspectj.git/commitdiff
declareMixin
authoraclement <aclement>
Tue, 3 Mar 2009 19:15:46 +0000 (19:15 +0000)
committeraclement <aclement>
Tue, 3 Mar 2009 19:15:46 +0000 (19:15 +0000)
weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java

index 413c71c2e3e319707a01fa49a2d98ab7423b560c..7730103ed8932e31a64335d7a40ac3ebdc5b20fa 100644 (file)
@@ -288,8 +288,13 @@ public class AtAjAttributes {
                        for (int j = 0; j < mattributes.length; j++) {
                                Attribute mattribute = mattributes[j];
                                if (acceptAttribute(mattribute)) {
-                                       mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler);// FIXME AVASM
+                                       // TODO speed all this nonsense up rather than looking through all the annotations every time
+                                       // same for fields
+                                       mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler);
                                        processedPointcut = handlePointcutAnnotation((RuntimeAnnotations) mattribute, mstruct);
+//                                     if (!processedPointcut) {
+//                                             handleDeclareMixinAnnotation((RuntimeAnnotations) mattribute, mstruct);
+//                                     }
                                        // there can only be one RuntimeVisible bytecode attribute
                                        break;
                                }
@@ -770,6 +775,160 @@ public class AtAjAttributes {
                return false;
        }
 
+       /**
+        * Process any @DeclareMixin annotation.
+        * 
+        * @param runtimeAnnotations
+        * @param struct
+        * @return true if found
+        */
+       private static boolean handleDeclareMixinAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) {
+               AnnotationGen declareMixinAnnotation = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREMIXIN_ANNOTATION);
+               if (declareMixinAnnotation != null) {
+                       ElementNameValuePairGen declareMixinPatternNameValuePair = getAnnotationElement(declareMixinAnnotation, VALUE);
+                       String declareMixinPattern = declareMixinPatternNameValuePair.getValue().stringifyValue();
+                       if (declareMixinPattern != null) {
+                               TypePattern typePattern = parseTypePattern(declareMixinPattern, struct);
+                               ResolvedType methodType = UnresolvedType.forSignature(struct.method.getSignature()).resolve(
+                                               struct.enclosingType.getWorld());
+                               // For @DeclareMixin:
+                               // methodType - might be a class or an interface. If a class then the interfaces value of the
+                               // annotation will subset it
+                               if (methodType.isInterface()) {
+                                       // TODO DECLAREMIXIN set the location more accurately than this
+                                       // TODO DECLAREMIXIN check for interfaces specified and if they aren't it is an error
+                                       TypePattern parent = parseTypePattern(methodType.getName(), struct);
+                                       FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
+                                       IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
+                                       // first add the declare implements like
+                                       List parents = new ArrayList(1);
+                                       parents.add(parent);
+                                       // how do we mark this as a decp due to decmixin?
+                                       DeclareParents dp = new DeclareParents(typePattern, parents, false);
+                                       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
+                                       typePattern = typePattern.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.setLocation(struct.context, -1, -1); // not ideal...
+                                       struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp));
+
+                                       // 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;
+                                       ResolvedMember[] methods = (ResolvedMember[]) methodType.getMethodsWithoutIterator(true, false).toArray(
+                                                       new ResolvedMember[0]);
+                                       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,
+                                                                       defaultImplClassName, typePattern);
+                                                       mdtm.setFieldType(methodType);
+                                                       mdtm.setSourceLocation(struct.enclosingType.getSourceLocation());
+                                                       struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm));
+                                               }
+                                       }
+                                       // successfull so far, we thus need a bcel type munger to have
+                                       // a field hosting the mixin in the target type
+                                       if (hasAtLeastOneMethod && defaultImplClassName != null) {
+                                               ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, methodType, struct.enclosingType);
+                                               struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger(
+                                                               fieldHost, struct.enclosingType, typePattern)));
+                                       }
+
+                                       return true;
+                               } else {
+                                       reportError("@DeclareParents: can only be used on a field whose type is an interface", struct);
+                                       return false;
+                               }
+                       }
+               }
+               return false;
+       }
+
        /**
         * Read @Before
         *