]> source.dussan.org Git - aspectj.git/commitdiff
259416: preliminary work paramAnnotationBinding
authorAndy Clement <aclement@pivotal.io>
Fri, 2 Dec 2016 18:32:17 +0000 (10:32 -0800)
committerAndy Clement <aclement@pivotal.io>
Fri, 2 Dec 2016 18:32:17 +0000 (10:32 -0800)
32 files changed:
org.aspectj.matcher/src/org/aspectj/weaver/Member.java
org.aspectj.matcher/src/org/aspectj/weaver/MemberImpl.java
org.aspectj.matcher/src/org/aspectj/weaver/Shadow.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/AnnotationPatternList.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java
org.aspectj.matcher/src/org/aspectj/weaver/reflect/AnnotationFinder.java
org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionShadow.java
org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionVar.java
org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java
tests/bugs1810/259416/Caveats [new file with mode: 0644]
tests/bugs1810/259416/ColouredAnnotation.class [new file with mode: 0644]
tests/bugs1810/259416/ColouredAnnotation.java [new file with mode: 0644]
tests/bugs1810/259416/Creating [new file with mode: 0644]
tests/bugs1810/259416/Downloading [new file with mode: 0644]
tests/bugs1810/259416/Filler.java [new file with mode: 0644]
tests/bugs1810/259416/RGB.class [new file with mode: 0644]
tests/bugs1810/259416/RGB.java [new file with mode: 0644]
tests/bugs1810/259416/Tapping [new file with mode: 0644]
tests/bugs1810/259416/Test1.java [new file with mode: 0644]
tests/bugs1810/259416/Test2.java [new file with mode: 0644]
tests/bugs1810/259416/Test3.java [new file with mode: 0644]
tests/bugs1810/259416/Test4.java [new file with mode: 0644]
tests/src/org/aspectj/systemtest/ajc1810/Ajc1810Tests.java
tests/src/org/aspectj/systemtest/ajc1810/ajc1810.xml
weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java [new file with mode: 0644]
weaver5/java5-src/org/aspectj/weaver/reflect/Java15AnnotationFinder.java
weaver5/java5-src/org/aspectj/weaver/reflect/ReflectiveAnnotationAJ.java [new file with mode: 0644]
weaver5/java5-testsrc/org/aspectj/weaver/tools/Java15PointcutExpressionTest.java

index 8134e8df2f612c6da4fea8fd2144a92fe6641f62..f3a11ff9b3feaefb18d30c47216b5e2c4a0c06df 100644 (file)
@@ -78,6 +78,8 @@ public interface Member extends Comparable<Member> {
         */
        public boolean canBeParameterized();
 
+       public AnnotationAJ[][] getParameterAnnotations();
+       
        public AnnotationAJ[] getAnnotations();
 
        public Collection<ResolvedType> getDeclaringTypes(World world);
index fbf497ed224f1e8c9774cac4394bf793a200d397..89e0e39e16cb07533e028fac5809d555a7c89301 100644 (file)
@@ -506,6 +506,11 @@ public class MemberImpl implements Member {
                }
                return resolved.getParameterNames();
        }
+       
+       public AnnotationAJ[][] getParameterAnnotations() {
+               throw new UnsupportedOperationException("You should resolve this member '" + this
+                               + "' and call getParameterAnnotations() on the result...");
+       }
 
        /**
         * All the signatures that a join point with this member as its signature has.
index 587d19c1564caff902c174809536dcdd190bb359..07c62aaa654709d785eef09d3a347bc1dc7a3023 100644 (file)
@@ -236,6 +236,8 @@ public abstract class Shadow {
 
        public abstract Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType);
 
+       public abstract Var getArgParamAnnotationVar(int i, UnresolvedType forAnnotationType);
+
        public abstract Member getEnclosingCodeSignature();
 
        /**
index 0b93b48d1763dc09ecff29b620bb76058c528476..af8827202bdd71ff0f6584e1ccf170e43f936d11 100644 (file)
@@ -14,10 +14,12 @@ import java.util.List;
 import java.util.Map;
 
 import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotationAJ;
 import org.aspectj.weaver.CompressingDataOutputStream;
 import org.aspectj.weaver.ISourceContext;
 import org.aspectj.weaver.IntMap;
 import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
 import org.aspectj.weaver.UnresolvedType;
 import org.aspectj.weaver.VersionedDataInputStream;
 import org.aspectj.weaver.World;
@@ -72,10 +74,11 @@ public class AnnotationPatternList extends PatternNode {
                        typePatterns[i].resolve(inWorld);
                }
        }
-
-       public FuzzyBoolean matches(ResolvedType[] someArgs) {
+       
+       public FuzzyBoolean matches(ResolvedType[] parameterTypes, Shadow shadow) {
+               ResolvedType[][] paramAnnotationTypes = null;
                // do some quick length tests first
-               int numArgsMatchedByEllipsis = (someArgs.length + ellipsisCount) - typePatterns.length;
+               int numArgsMatchedByEllipsis = (parameterTypes.length + ellipsisCount) - typePatterns.length;
                if (numArgsMatchedByEllipsis < 0) {
                        return FuzzyBoolean.NO;
                }
@@ -91,14 +94,26 @@ public class AnnotationPatternList extends PatternNode {
                                argsIndex += numArgsMatchedByEllipsis;
                        } else if (typePatterns[i] == AnnotationTypePattern.ANY) {
                                argsIndex++;
+                       } else if (typePatterns[i].isForParameterAnnotationMatch()) {
+                               if (paramAnnotationTypes == null) {
+                                       paramAnnotationTypes = shadow.getResolvedSignature().getParameterAnnotationTypes();
+                               }
+                               ExactAnnotationTypePattern ap = (ExactAnnotationTypePattern) typePatterns[i];
+                               FuzzyBoolean matches = ap.matches(null, paramAnnotationTypes.length==0?ResolvedType.NONE:paramAnnotationTypes[argsIndex]);
+                               if (matches == FuzzyBoolean.NO) {
+                                       return FuzzyBoolean.NO;
+                               } else {
+                                       argsIndex++;
+                                       ret = ret.and(matches);
+                               }
                        } else {
                                // match the argument type at argsIndex with the ExactAnnotationTypePattern
                                // we know it is exact because nothing else is allowed in args
-                               if (someArgs[argsIndex].isPrimitiveType()) {
+                               if (parameterTypes[argsIndex].isPrimitiveType()) {
                                        return FuzzyBoolean.NO; // can never match
                                }
                                ExactAnnotationTypePattern ap = (ExactAnnotationTypePattern) typePatterns[i];
-                               FuzzyBoolean matches = ap.matchesRuntimeType(someArgs[argsIndex]);
+                               FuzzyBoolean matches = ap.matchesRuntimeType(parameterTypes[argsIndex]);
                                if (matches == FuzzyBoolean.NO) {
                                        return FuzzyBoolean.MAYBE; // could still match at runtime
                                } else {
@@ -110,6 +125,47 @@ public class AnnotationPatternList extends PatternNode {
                return ret;
        }
 
+       public FuzzyBoolean matches(ResolvedType[] someArgs) {
+               // do some quick length tests first
+               int numArgsMatchedByEllipsis = (someArgs.length + ellipsisCount) - typePatterns.length;
+               if (numArgsMatchedByEllipsis < 0) {
+                       return FuzzyBoolean.NO;
+               }
+               if ((numArgsMatchedByEllipsis > 0) && (ellipsisCount == 0)) {
+                       return FuzzyBoolean.NO;
+               }
+               // now work through the args and the patterns, skipping at ellipsis
+               FuzzyBoolean ret = FuzzyBoolean.YES;
+               int argsIndex = 0;
+               for (int i = 0; i < typePatterns.length; i++) {
+                       if (typePatterns[i] == AnnotationTypePattern.ELLIPSIS) {
+                               // match ellipsisMatchCount args
+                               argsIndex += numArgsMatchedByEllipsis;
+                       } else if (typePatterns[i] == AnnotationTypePattern.ANY) {
+                               argsIndex++;
+                       } else {
+                               // match the argument type at argsIndex with the ExactAnnotationTypePattern
+                               // we know it is exact because nothing else is allowed in args
+                               if (someArgs[argsIndex].isPrimitiveType()) {
+                                       return FuzzyBoolean.NO; // can never match
+                               }
+                               ExactAnnotationTypePattern ap = (ExactAnnotationTypePattern) typePatterns[i];
+//                             if (ap.isForParameterAnnotationMatch()) {
+//                                     ap.matches(null,)
+//                             } else {
+                                       FuzzyBoolean matches = ap.matchesRuntimeType(someArgs[argsIndex]);
+                                       if (matches == FuzzyBoolean.NO) {
+                                               return FuzzyBoolean.MAYBE; // could still match at runtime
+                                       } else {
+                                               argsIndex++;
+                                               ret = ret.and(matches);
+                                       }
+//                             }
+                       }
+               }
+               return ret;
+       }
+
        public int size() {
                return typePatterns.length;
        }
index db612b8cd2a7263ab9f3174ca60c63cb63bfb3ae..9eeaf5b2ce709f8c3673f937732abde44182cfca 100644 (file)
@@ -76,15 +76,11 @@ public class ArgsAnnotationPointcut extends NameBindingPointcut {
                return FuzzyBoolean.MAYBE;
        }
 
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
-        */
        protected FuzzyBoolean matchInternal(Shadow shadow) {
                arguments.resolve(shadow.getIWorld());
-               FuzzyBoolean ret = arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()));
-               return ret;
+               FuzzyBoolean ret1 = arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()),shadow);
+//             FuzzyBoolean ret2 = arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()));
+               return ret1;
        }
 
        /*
@@ -166,12 +162,22 @@ public class ArgsAnnotationPointcut extends NameBindingPointcut {
                                ResolvedType rAnnType = ap.getAnnotationType().resolve(shadow.getIWorld());
                                if (ap instanceof BindingAnnotationTypePattern) {
                                        BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) ap;
-                                       Var annvar = shadow.getArgAnnotationVar(argsIndex, rAnnType);
-                                       state.set(btp.getFormalIndex(), annvar);
+                                       Var v = btp.isForParameterAnnotationMatch() ?
+                                                       shadow.getArgParamAnnotationVar(argsIndex, rAnnType) :
+                                                       shadow.getArgAnnotationVar(argsIndex, rAnnType);
+                                       state.set(btp.getFormalIndex(), v);
                                }
-                               if (!ap.matches(rArgType).alwaysTrue()) {
-                                       // we need a test...
-                                       ret = Test.makeAnd(ret, Test.makeHasAnnotation(shadow.getArgVar(argsIndex), rAnnType));
+                               if (ap.isForParameterAnnotationMatch()) {
+                                       if (!ap.matches(null,new ResolvedType[] {rAnnType}).alwaysTrue()) {
+                                               if (true) throw new IllegalStateException();
+                                               // need something intelligent here...
+                                               ret = Test.makeAnd(ret, Test.makeHasAnnotation(shadow.getArgVar(argsIndex), rAnnType));
+                                       }
+                               } else {
+                                       if (!ap.matches(rAnnType).alwaysTrue()) {
+                                               // we need a test...
+                                               ret = Test.makeAnd(ret, Test.makeHasAnnotation(shadow.getArgVar(argsIndex), rAnnType));
+                                       }
                                }
                                argsIndex++;
                        }
index 142f6155e8e7817a39eb64a8299864503a87ef55..f8e27ad2e7a0ba4e655038d377729368286c1540 100644 (file)
@@ -29,9 +29,6 @@ public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern imp
 
        protected int formalIndex;
 
-       /**
-        * @param annotationType
-        */
        public BindingAnnotationTypePattern(UnresolvedType annotationType, int index) {
                super(annotationType, null);
                this.formalIndex = index;
@@ -107,12 +104,17 @@ public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern imp
        }
 
        public AnnotationTypePattern remapAdviceFormals(IntMap bindings) {
+               AnnotationTypePattern atp;
                if (!bindings.hasKey(formalIndex)) {
-                       return new ExactAnnotationTypePattern(annotationType, null);
+                       atp = new ExactAnnotationTypePattern(annotationType, null);
                } else {
                        int newFormalIndex = bindings.get(formalIndex);
-                       return new BindingAnnotationTypePattern(annotationType, newFormalIndex);
+                       atp = new BindingAnnotationTypePattern(annotationType, newFormalIndex);
+                       if (this.isForParameterAnnotationMatch()) {
+                               atp.setForParameterAnnotationMatch();
+                       }
                }
+               return atp;
        }
 
        private static final byte VERSION = 1; // rev if serialised form changed
@@ -124,6 +126,7 @@ public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern imp
                annotationType.write(s);
                s.writeShort((short) formalIndex);
                writeLocation(s);
+               s.writeBoolean(isForParameterAnnotationMatch());
        }
 
        public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
@@ -133,6 +136,8 @@ public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern imp
                }
                AnnotationTypePattern ret = new BindingAnnotationTypePattern(UnresolvedType.read(s), s.readShort());
                ret.readLocation(context, s);
+               if (s.readBoolean()) 
+                       ret.setForParameterAnnotationMatch();
                return ret;
        }
 }
index 772e8f6ca64678e7c327b75cc31f83e2d5ef4030..0ee8a3369c03ff94f2c238b27959f5fa9c09d732 100644 (file)
@@ -43,6 +43,7 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
        protected boolean resolved = false;
        protected boolean bindingPattern = false;
        private Map<String, String> annotationValues;
+       private int annotationNumber;
 
        // OPTIMIZE is annotationtype really unresolved???? surely it is resolved by
        // now...
@@ -232,6 +233,7 @@ public class ExactAnnotationTypePattern extends AnnotationTypePattern {
                                                                                                .error("Compiler limitation: annotation value matching for parameter annotations not yet supported"));
                                                return FuzzyBoolean.NO;
                                        }
+                                       this.annotationNumber= i;
                                        return FuzzyBoolean.YES;
                                }
                        }
index 106376aada0a94afeee16d81d8e92dc12147ad68..8f3068ac19e8aa2eaf46aeb80438f3d691f76da7 100644 (file)
@@ -1174,9 +1174,15 @@ public class PatternParser {
                p.setLocation(sourceContext, startPos, endPos);
                // For optimized syntax that allows binding directly to annotation values (pr234943)
                if (maybeEat("(")) {
-                       String formalName = parseIdentifier();
-                       p = new ExactAnnotationFieldTypePattern(p, formalName);
-                       eat(")");
+                       if (maybeEat("*")) {
+                               // Attempt to bind parameter annotation:   @args(@SomeParamAnnotation (*),..)
+                               p.setForParameterAnnotationMatch();
+                               eat(")");
+                       } else {
+                               String formalName = parseIdentifier();
+                               p = new ExactAnnotationFieldTypePattern(p, formalName);
+                               eat(")");
+                       }
                }
                return p;
        }
index 7efeac9aec0ad634bcd8ab66c78005d25463929a..5e1957f20b1dab356b1d64c200ada05d9171d83c 100644 (file)
@@ -1,5 +1,5 @@
 /* *******************************************************************
- * Copyright (c) 2005 Contributors.
+ * Copyright (c) 2005-2016 Contributors.
  * All rights reserved. 
  * This program and the accompanying materials are made available 
  * under the terms of the Eclipse Public License v1.0 
@@ -20,7 +20,10 @@ import org.aspectj.weaver.UnresolvedType;
 import org.aspectj.weaver.World;
 
 /**
- * @author colyer Used in 1.4 code to access annotations safely
+ * Used in 1.4 code to access annotations safely.
+ * 
+ * @author Adrian Colyer 
+ * @author Andy Clement
  */
 public interface AnnotationFinder {
 
@@ -32,14 +35,15 @@ public interface AnnotationFinder {
 
        Object getAnnotationFromMember(ResolvedType annotationType, Member aMember);
 
-       public AnnotationAJ getAnnotationOfType(UnresolvedType ofType,
-                       Member onMember);
+       AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember);
 
-       public String getAnnotationDefaultValue(Member onMember);
+       String getAnnotationDefaultValue(Member onMember);
 
-       Object getAnnotationFromClass(ResolvedType annotationType, Class aClass);
+       Object getAnnotationFromClass(ResolvedType annotationType, Class<?> aClass);
 
-       Set/* ResolvedType */getAnnotations(Member onMember);
+       Set<ResolvedType> getAnnotations(Member onMember);
 
        ResolvedType[][] getParameterAnnotationTypes(Member onMember);
+
+       Object getParamAnnotation(Member subject, int argsIndex, int paramAnnoIndex);
 }
index 0c6277e5998bf4251a9e4bbe3b4b1d7e5b003f46..4e6e0cef8060f4ca05c56659225c4fdee32bb830 100644 (file)
@@ -28,8 +28,8 @@ import org.aspectj.weaver.ast.Var;
 import org.aspectj.weaver.tools.MatchingContext;
 
 /**
- * @author colyer
- * 
+ * @author Adrian Colyer
+ * @author Andy Clement
  */
 public class ReflectionShadow extends Shadow {
 
@@ -42,10 +42,11 @@ public class ReflectionShadow extends Shadow {
        private Var[] argsVars = null;
        private Var atThisVar = null;
        private Var atTargetVar = null;
-       private Map atArgsVars = new HashMap();
-       private Map withinAnnotationVar = new HashMap();
-       private Map withinCodeAnnotationVar = new HashMap();
-       private Map annotationVar = new HashMap();
+       private Map<ResolvedType,Var[]> atArgsVars = new HashMap<>();
+       private Map<ResolvedType,Var[]> atArgParamVars = new HashMap<>();
+       private Map<ResolvedType,Var> withinAnnotationVar = new HashMap<>();
+       private Map<ResolvedType,Var> withinCodeAnnotationVar = new HashMap<>();
+       private Map<ResolvedType,Var> annotationVar = new HashMap<>();
        private AnnotationFinder annotationFinder;
 
        public static Shadow makeExecutionShadow(World inWorld, java.lang.reflect.Member forMethod, MatchingContext withContext) {
@@ -311,11 +312,6 @@ public class ReflectionShadow extends Shadow {
                return atTargetVar;
        }
 
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.aspectj.weaver.Shadow#getArgAnnotationVar(int, org.aspectj.weaver.UnresolvedType)
-        */
        public Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType) {
                ResolvedType annType = forAnnotationType.resolve(world);
                if (atArgsVars.get(annType) == null) {
@@ -330,6 +326,27 @@ public class ReflectionShadow extends Shadow {
                }
                return vars[i];
        }
+       
+       public Var getArgParamAnnotationVar(int i, UnresolvedType forAnnotationType) {
+               ResolvedType resolvedAnnotationType = forAnnotationType.resolve(world);
+               if (atArgParamVars.get(resolvedAnnotationType) == null) {
+                       Var[] vars = new Var[getArgCount()];
+                       atArgParamVars.put(resolvedAnnotationType, vars);
+               }
+               Var[] vars = (Var[]) atArgParamVars.get(resolvedAnnotationType);
+               if (i > (vars.length - 1))
+                       return null;
+               if (vars[i] == null) {
+                       ResolvedMember rm = getSignature().resolve(world);
+                       ResolvedType[] paramAnnos = rm.getParameterAnnotationTypes()[i];
+                       for (int j=0;j<paramAnnos.length;j++) {
+                               if (paramAnnos[j].equals(resolvedAnnotationType)) {
+                                       vars[i] = ReflectionVar.createArgsParamAnnotationVar(resolvedAnnotationType, i, j, this.annotationFinder); 
+                               }
+                       }
+               }
+               return vars[i];
+       }
 
        /*
         * (non-Javadoc)
index 59876a737219536d1dbe83fa4cf7b9522fe3a72f..542d36cadef4dd1ef5be62f38b9be21cbe21981a 100644 (file)
@@ -30,6 +30,7 @@ public final class ReflectionVar extends Var {
        static final int AT_WITHIN_VAR = 6;
        static final int AT_WITHINCODE_VAR = 7;
        static final int AT_ANNOTATION_VAR = 8;
+       static final int AT_ARGS_PARAM_ANNO_VAR = 9;
        
        private AnnotationFinder annotationFinder = null;
        
@@ -48,6 +49,7 @@ public final class ReflectionVar extends Var {
 //     }
        
        private int argsIndex = 0;
+       private int paramAnnoIndex;
        private int varType;
        
        public static ReflectionVar createThisVar(ResolvedType type,AnnotationFinder finder) {
@@ -87,6 +89,14 @@ public final class ReflectionVar extends Var {
                ret.argsIndex = index;
                return ret;             
        }
+
+       public static ReflectionVar createArgsParamAnnotationVar(ResolvedType type, int index, int paramAnnoIndex, AnnotationFinder finder) {
+               ReflectionVar ret = new ReflectionVar(type,finder);
+               ret.varType = AT_ARGS_PARAM_ANNO_VAR;
+               ret.argsIndex = index;
+               ret.paramAnnoIndex = paramAnnoIndex;
+               return ret;             
+       }
        
        public static ReflectionVar createWithinAnnotationVar(ResolvedType annType, AnnotationFinder finder) {
                ReflectionVar ret = new ReflectionVar(annType,finder);
@@ -106,7 +116,7 @@ public final class ReflectionVar extends Var {
                return ret;
        }
 
-       private ReflectionVar(ResolvedType type,AnnotationFinder finder) {
+       private ReflectionVar(ResolvedType type, AnnotationFinder finder) {
                super(type);
                this.annotationFinder = finder;
        }
@@ -115,9 +125,11 @@ public final class ReflectionVar extends Var {
        public Object getBindingAtJoinPoint(Object thisObject, Object targetObject, Object[] args) {
                return getBindingAtJoinPoint(thisObject,targetObject,args,null,null,null);
        }
+       
        /**
         * At a join point with the given this, target, and args, return the object to which this
         * var is bound.
+        * 
         * @param thisObject
         * @param targetObject
         * @param args
@@ -149,6 +161,11 @@ public final class ReflectionVar extends Var {
                        if (annotationFinder != null) {
                                return annotationFinder.getAnnotation(getType(), args[argsIndex]);
                        } else return null;
+               case AT_ARGS_PARAM_ANNO_VAR:
+                       if (this.argsIndex > (args.length - 1)) return null;
+                       if (annotationFinder != null) {
+                               return annotationFinder.getParamAnnotation(subject, argsIndex, paramAnnoIndex);
+                       } else return null;
                case AT_WITHIN_VAR:
                        if (annotationFinder != null) {
                                return annotationFinder.getAnnotationFromClass(getType(), withinType);
index c151b228e3e0fd1c5b4169375edc338dc7a39a87..0594a8ff656a360858128a93a94025c88749d56b 100644 (file)
@@ -44,10 +44,10 @@ public class StandardShadow extends Shadow {
        private Var[] argsVars = null;
        private Var atThisVar = null;
        private Var atTargetVar = null;
-       private Map atArgsVars = new HashMap();
-       private Map withinAnnotationVar = new HashMap();
-       private Map withinCodeAnnotationVar = new HashMap();
-       private Map annotationVar = new HashMap();
+       private Map<ResolvedType,Var[]> atArgsVars = new HashMap<>();
+       private Map<ResolvedType,Var> withinAnnotationVar = new HashMap<>();
+       private Map<ResolvedType,Var> withinCodeAnnotationVar = new HashMap<>();
+       private Map<ResolvedType,Var> annotationVar = new HashMap<>();
        private AnnotationFinder annotationFinder;
 
        public static Shadow makeExecutionShadow(World inWorld, java.lang.reflect.Member forMethod, MatchingContext withContext) {
diff --git a/tests/bugs1810/259416/Caveats b/tests/bugs1810/259416/Caveats
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/bugs1810/259416/ColouredAnnotation.class b/tests/bugs1810/259416/ColouredAnnotation.class
new file mode 100644 (file)
index 0000000..ff8b195
Binary files /dev/null and b/tests/bugs1810/259416/ColouredAnnotation.class differ
diff --git a/tests/bugs1810/259416/ColouredAnnotation.java b/tests/bugs1810/259416/ColouredAnnotation.java
new file mode 100644 (file)
index 0000000..1886a2f
--- /dev/null
@@ -0,0 +1,6 @@
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ColouredAnnotation {
+  RGB value();
+}
diff --git a/tests/bugs1810/259416/Creating b/tests/bugs1810/259416/Creating
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/bugs1810/259416/Downloading b/tests/bugs1810/259416/Downloading
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/bugs1810/259416/Filler.java b/tests/bugs1810/259416/Filler.java
new file mode 100644 (file)
index 0000000..dc5592b
--- /dev/null
@@ -0,0 +1,5 @@
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Filler {
+}
diff --git a/tests/bugs1810/259416/RGB.class b/tests/bugs1810/259416/RGB.class
new file mode 100644 (file)
index 0000000..737e3b6
Binary files /dev/null and b/tests/bugs1810/259416/RGB.class differ
diff --git a/tests/bugs1810/259416/RGB.java b/tests/bugs1810/259416/RGB.java
new file mode 100644 (file)
index 0000000..04d4e94
--- /dev/null
@@ -0,0 +1,3 @@
+public enum RGB {
+  RED, GREEN, BLUE;
+}
diff --git a/tests/bugs1810/259416/Tapping b/tests/bugs1810/259416/Tapping
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/bugs1810/259416/Test1.java b/tests/bugs1810/259416/Test1.java
new file mode 100644 (file)
index 0000000..e4961f0
--- /dev/null
@@ -0,0 +1,13 @@
+public class Test1 {
+  public static void main(String[] argv) {
+    coloured("abc");
+  }
+  public static void coloured(@ColouredAnnotation(RGB.RED) String param1) {}
+}
+
+aspect X {
+  // execution(@ColouredAnnotation * colouredMethod(..)) && @annotation(ColouredAnnotation(colour));
+  before(ColouredAnnotation ca):  execution(* *(@ColouredAnnotation (*))) && @args(ca (*)) {
+    System.out.println("Annotation from parameter on method "+thisJoinPoint+" is "+ca);
+  }
+}
diff --git a/tests/bugs1810/259416/Test2.java b/tests/bugs1810/259416/Test2.java
new file mode 100644 (file)
index 0000000..a2a026d
--- /dev/null
@@ -0,0 +1,13 @@
+public class Test2 {
+  public static void main(String[] argv) {
+    coloured("abc");
+  }
+  public static void coloured(@ColouredAnnotation(RGB.GREEN) String param1) {}
+}
+
+aspect X {
+  // execution(@ColouredAnnotation * colouredMethod(..)) && @annotation(ColouredAnnotation(colour));
+  before(ColouredAnnotation ca):  execution(* *(..)) && @args(ca (*)) {
+    System.out.println("Annotation from parameter on method "+thisJoinPoint+" is "+ca);
+  }
+}
diff --git a/tests/bugs1810/259416/Test3.java b/tests/bugs1810/259416/Test3.java
new file mode 100644 (file)
index 0000000..49744de
--- /dev/null
@@ -0,0 +1,13 @@
+public class Test3 {
+  public static void main(String[] argv) {
+    coloured(1,"abc");
+  }
+  public static void coloured(int param1, @ColouredAnnotation(RGB.RED) String param2) {}
+}
+
+aspect X {
+  // execution(@ColouredAnnotation * colouredMethod(..)) && @annotation(ColouredAnnotation(colour));
+  before(ColouredAnnotation ca):  execution(* *(..)) && @args(*, ca (*)) {
+    System.out.println("Annotation from parameter on method "+thisJoinPoint+" is "+ca);
+  }
+}
diff --git a/tests/bugs1810/259416/Test4.java b/tests/bugs1810/259416/Test4.java
new file mode 100644 (file)
index 0000000..92324f8
--- /dev/null
@@ -0,0 +1,13 @@
+public class Test4 {
+  public static void main(String[] argv) {
+    coloured(1,"abc");
+  }
+  public static void coloured(int param1, @Filler @ColouredAnnotation(RGB.GREEN) String param2) {}
+}
+
+aspect X {
+  // execution(@ColouredAnnotation * colouredMethod(..)) && @annotation(ColouredAnnotation(colour));
+  before(ColouredAnnotation ca):  execution(* *(..)) && @args(*, ca (*)) {
+    System.out.println("Annotation from parameter on method "+thisJoinPoint+" is "+ca);
+  }
+}
index 3cae1378cdde813a0b8da271f72a8c1ce0f7f5eb..36232a91d8120893a8d583b33c046e49d388e193 100644 (file)
@@ -24,6 +24,42 @@ import junit.framework.Test;
  */
 public class Ajc1810Tests extends org.aspectj.testing.XMLBasedAjcTestCase {
 
+       // Basic with execution(* *(@Foo (*))) && @args(ca (*))
+       public void testParamAnnoBinding_259416_1() {
+               runTest("param anno binding");
+       }
+
+       // Basic with execution(* *(..)) && args(ca (*))
+       public void testParamAnnoBinding_259416_2() {
+               runTest("param anno binding 2");
+       }
+
+       // Basic with execution(* *(..)) && args(*,ca (*))
+       public void testParamAnnoBinding_259416_3() {
+               runTest("param anno binding 3");
+       }
+
+       // Basic with execution(* *(..)) && args(*,ca (*)) where target has two parameter annotations and we match the 2nd one
+       public void testParamAnnoBinding_259416_4() {
+               runTest("param anno binding 4");
+       }
+       
+       // execution(* *(..)) && args(f *,ca (*))
+       
+       // args(ca1 (*),ca2 (*))
+       
+       // args(ca(*))
+       
+       // args(ca1 (f))
+       
+       // args(ca1 ba1 (*))
+       
+       // args(ca1 ba1 (f1 f2))
+       
+       // args(ca1 (*), .., ca2 (*))
+       
+       
+       
        public void testBinding_500035() {
                runTest("ataspectj binding");
        }
index 7485c1c20816bdd7ce696ebd38814f23d7077bb6..75edcbc5edabf7ed9293938f63f22604d1710bf6 100644 (file)
@@ -2,6 +2,51 @@
 
 <suite>
 
+       <ajc-test dir="bugs1810/259416" title="param anno binding">
+               <compile options="-1.8 -showWeaveInfo" files="RGB.java ColouredAnnotation.java Test1.java">
+                 <message kind="weave" text="Join point 'method-execution(void Test1.coloured(java.lang.String))' in Type 'Test1' (Test1.java:5) advised by before advice from 'X' (Test1.java:10)"/>
+               </compile>
+               <run class="Test1">
+                       <stdout>
+                               <line text="Annotation from parameter on method execution(void Test1.coloured(String)) is @ColouredAnnotation(value=RED)"/>
+                       </stdout>
+               </run>
+       </ajc-test>
+       
+       <ajc-test dir="bugs1810/259416" title="param anno binding 2">
+               <compile options="-1.8 -showWeaveInfo" files="RGB.java ColouredAnnotation.java Test2.java">
+                 <message kind="weave" text="Join point 'method-execution(void Test2.coloured(java.lang.String))' in Type 'Test2' (Test2.java:5) advised by before advice from 'X' (Test2.java:10)"/>
+               </compile>
+               <run class="Test2">
+                       <stdout>
+                               <line text="Annotation from parameter on method execution(void Test2.coloured(String)) is @ColouredAnnotation(value=GREEN)"/>
+                       </stdout>
+               </run>
+       </ajc-test>
+       
+       <ajc-test dir="bugs1810/259416" title="param anno binding 3">
+               <compile options="-1.8 -showWeaveInfo" files="RGB.java ColouredAnnotation.java Test3.java">
+                 <message kind="weave" text="Join point 'method-execution(void Test3.coloured(int, java.lang.String))' in Type 'Test3' (Test3.java:5) advised by before advice from 'X' (Test3.java:10)"/>
+               </compile>
+               <run class="Test3">
+                       <stdout>
+                               <line text="Annotation from parameter on method execution(void Test3.coloured(int, String)) is @ColouredAnnotation(value=RED)"/>
+                       </stdout>
+               </run>
+       </ajc-test>
+       
+       <ajc-test dir="bugs1810/259416" title="param anno binding 4">
+               <compile options="-1.8 -showWeaveInfo" files="RGB.java ColouredAnnotation.java Test4.java Filler.java">
+                 <message kind="weave" text="Join point 'method-execution(void Test4.coloured(int, java.lang.String))' in Type 'Test4' (Test4.java:5) advised by before advice from 'X' (Test4.java:10)"/>
+               </compile>
+               <run class="Test4">
+                       <stdout>
+                               <line text="Annotation from parameter on method execution(void Test4.coloured(int, String)) is @ColouredAnnotation(value=GREEN)"/>
+                       </stdout>
+               </run>
+       </ajc-test>
+       
+
        <ajc-test dir="bugs1810/500035" title="ataspectj binding">
                <compile options="-1.8" files="Code.java"/>
                <run class="Code">
index 10fdbd05ceb5ca2c25aa9beb52bc94d0cc2cdddc..914e996978fe17d1f84e9b1bc0a4a62508a699dc 100644 (file)
@@ -875,6 +875,7 @@ public class BcelShadow extends Shadow {
        private BcelVar targetVar = null;
        private BcelVar[] argVars = null;
        private Map<ResolvedType, AnnotationAccessVar> kindedAnnotationVars = null;
+       private Map<ResolvedType,AnnotationAccessVar>[] paramAnnoVars = null;
        private Map<ResolvedType, TypeAnnotationAccessVar> thisAnnotationVars = null;
        private Map<ResolvedType, TypeAnnotationAccessVar> targetAnnotationVars = null;
        // private Map/* <UnresolvedType,BcelVar> */[] argAnnotationVars = null;
@@ -952,6 +953,12 @@ public class BcelShadow extends Shadow {
                return kindedAnnotationVars.get(forAnnotationType);
        }
 
+       @Override
+       public Var getArgParamAnnotationVar(int parameterIndex, UnresolvedType forAnnotationType) {
+               initializeKindedAnnotationVars();
+               return paramAnnoVars[parameterIndex].get(forAnnotationType);
+       }
+
        @Override
        public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) {
                initializeWithinAnnotationVars();
@@ -1538,6 +1545,41 @@ public class BcelShadow extends Shadow {
                }
                return foundMember.getAnnotationTypes();
        }
+       
+       protected ResolvedType[][] getParameterAnnotations(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) {
+               if (foundMember == null) {
+                       // check the ITD'd dooberries
+                       List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers();
+                       for (Iterator<ConcreteTypeMunger> iter = mungers.iterator(); iter.hasNext();) {
+                               Object munger = iter.next();
+                               ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) munger;
+                               if (typeMunger.getMunger() instanceof NewMethodTypeMunger
+                                               || typeMunger.getMunger() instanceof NewConstructorTypeMunger) {
+                                       ResolvedMember fakerm = typeMunger.getSignature();
+                                       // if (fakerm.hasAnnotations())
+
+                                       ResolvedMember ajcMethod = (getSignature().getKind() == ResolvedMember.CONSTRUCTOR ? AjcMemberMaker
+                                                       .postIntroducedConstructor(typeMunger.getAspectType(), fakerm.getDeclaringType(),
+                                                                       fakerm.getParameterTypes()) : AjcMemberMaker.interMethodDispatcher(fakerm,
+                                                       typeMunger.getAspectType()));
+                                       // AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType()));
+                                       ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
+                                       if (fakerm.getName().equals(getSignature().getName())
+                                                       && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) {
+                                               relevantType = typeMunger.getAspectType();
+                                               foundMember = rmm;
+                                               return foundMember.getParameterAnnotationTypes();
+                                       }
+                               }
+                       }
+                       // didn't find in ITDs, look in supers
+                       foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember);
+                       if (foundMember == null) {
+                               throw new IllegalStateException("Couldn't find member " + relevantMember + " for type " + relevantType);
+                       }
+               }
+               return foundMember.getParameterAnnotationTypes();
+       }
 
        /**
         * By determining what "kind" of shadow we are, we can find out the annotations on the appropriate element (method, field,
@@ -1550,6 +1592,7 @@ public class BcelShadow extends Shadow {
                kindedAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>();
 
                ResolvedType[] annotations = null;
+               ResolvedType[][] paramAnnotations = null;
                Member shadowSignature = getSignature();
                Member annotationHolder = getSignature();
                ResolvedType relevantType = shadowSignature.getDeclaringType().resolve(world);
@@ -1564,6 +1607,7 @@ public class BcelShadow extends Shadow {
                } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) {
                        ResolvedMember foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(), getSignature());
                        annotations = getAnnotations(foundMember, shadowSignature, relevantType);
+                       paramAnnotations = getParameterAnnotations(foundMember, shadowSignature, relevantType);
                        annotationHolder = getRelevantMember(foundMember, shadowSignature, relevantType);
                        relevantType = annotationHolder.getDeclaringType().resolve(world);
                } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) {
@@ -1589,17 +1633,15 @@ public class BcelShadow extends Shadow {
 
                } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution
                                || getKind() == Shadow.AdviceExecution) {
-
                        ResolvedMember foundMember = findMethod2(relevantType.getDeclaredMethods(), getSignature());
                        annotations = getAnnotations(foundMember, shadowSignature, relevantType);
+                       paramAnnotations = getParameterAnnotations(foundMember, shadowSignature, relevantType);
                        annotationHolder = getRelevantMember(foundMember, annotationHolder, relevantType);
                        UnresolvedType ut = annotationHolder.getDeclaringType();
                        relevantType = ut.resolve(world);
-
                } else if (getKind() == Shadow.ExceptionHandler) {
                        relevantType = getSignature().getParameterTypes()[0].resolve(world);
                        annotations = relevantType.getAnnotationTypes();
-
                } else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) {
                        ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(), getSignature());
                        annotations = found.getAnnotationTypes();
@@ -1615,6 +1657,22 @@ public class BcelShadow extends Shadow {
                                        annotationHolder, false);
                        kindedAnnotationVars.put(annotationType, accessVar);
                }
+               
+               if (paramAnnotations != null) {
+                       int max = paramAnnotations.length;
+                       paramAnnoVars = new HashMap[max];
+                       for (int p=0;p<max;p++) {
+                               ResolvedType[] annotationsOnParticularParam = paramAnnotations[p];
+                               paramAnnoVars[p] = new HashMap<ResolvedType,AnnotationAccessVar>();
+                               for (int i=0;i<annotationsOnParticularParam.length;i++) {
+//                             for (ResolvedType annotationOnParticularParam: annotationsOnParticularParam) {
+                                       ResolvedType annotationOnParticularParam = annotationsOnParticularParam[i];
+                                       ParamAnnotationAccessVar paramAccessVar = new ParamAnnotationAccessVar(this, getKind(), annotationOnParticularParam, relevantType,
+                                                       annotationHolder, false, p, i);
+                                       paramAnnoVars[p].put(annotationOnParticularParam, paramAccessVar);
+                               }
+                       }
+               }
        }
 
        private ResolvedMember findMethod2(ResolvedMember members[], Member sig) {
diff --git a/weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java
new file mode 100644 (file)
index 0000000..e3cebc3
--- /dev/null
@@ -0,0 +1,206 @@
+/* *******************************************************************
+ * Copyright (c) 2016 Contributors
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement     initial implementation 
+ * ******************************************************************/
+package org.aspectj.weaver.bcel;
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Field;
+import org.aspectj.apache.bcel.generic.Instruction;
+import org.aspectj.apache.bcel.generic.InstructionBranch;
+import org.aspectj.apache.bcel.generic.InstructionConstants;
+import org.aspectj.apache.bcel.generic.InstructionFactory;
+import org.aspectj.apache.bcel.generic.InstructionHandle;
+import org.aspectj.apache.bcel.generic.InstructionList;
+import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.Type;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.Shadow.Kind;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * Represents access to an parameter annotation on a member element.
+ */
+public class ParamAnnotationAccessVar extends AnnotationAccessVar {
+
+       private BcelShadow shadow;
+       private Kind kind; // What kind of shadow are we at?
+       private UnresolvedType containingType; // The type upon which we want to ask for 'member'
+       private Member member; // Holds the member that has the annotations (for method/field join points)
+       private boolean isWithin; // implies @within() or @withincode(). If false, that implies @annotation()
+       private int parameterNumber;
+       private int annotationOnParameterNumber;
+
+       public ParamAnnotationAccessVar(BcelShadow shadow, Kind kind, ResolvedType annotationType, 
+                       UnresolvedType theTargetIsStoredHere, Member sig, boolean isWithin, int parameterNumber, int annotationOnParameterNumber) {
+               super(shadow, kind, annotationType, theTargetIsStoredHere, sig, isWithin);
+               this.shadow = shadow;
+               this.kind = kind;
+               this.containingType = theTargetIsStoredHere;
+               this.member = sig;
+               this.isWithin = isWithin;
+               this.parameterNumber = parameterNumber;
+               this.annotationOnParameterNumber = annotationOnParameterNumber;
+       }
+
+       @Override
+       public String toString() {
+               return "ParamAnnotationAccessVar(" + getType() + ")";
+       }
+
+       private InstructionList createLoadInstructions(ResolvedType toType, InstructionFactory fact) {
+               InstructionList il = new InstructionList();
+               Type jlClass = BcelWorld.makeBcelType(UnresolvedType.JL_CLASS);
+               Type jlString = BcelWorld.makeBcelType(UnresolvedType.JL_STRING);
+               Type jlClassArray = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_CLASS_ARRAY);
+               Type jlaAnnotation = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_ANNOTATION);
+               Type jlaAnnotationArrayArray = BcelWorld.makeBcelType(UnresolvedType.makeArray(UnresolvedType.JAVA_LANG_ANNOTATION, 2));
+               Instruction pushConstant = fact.createConstant(new ObjectType(toType.getName()));
+               if (kind == Shadow.MethodCall || kind == Shadow.MethodExecution || kind == Shadow.PreInitialization
+                               || kind == Shadow.Initialization || kind == Shadow.ConstructorCall || kind == Shadow.ConstructorExecution
+                               || kind == Shadow.AdviceExecution ||
+                               // annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD
+                               ((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD)) {
+
+                       Type jlrMethod = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/reflect/Method;"));
+                       Type jlAnnotation = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/annotation/Annotation;"));
+                       Type[] paramTypes = BcelWorld.makeBcelTypes(member.getParameterTypes());
+
+                       if (kind == Shadow.MethodCall
+                                       || kind == Shadow.MethodExecution
+                                       || kind == Shadow.AdviceExecution
+                                       ||
+                                       // annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD
+                                       ((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD)
+                                       || ((kind == Shadow.ConstructorCall || kind == Shadow.ConstructorExecution) && member.getKind() == Member.METHOD)) {
+
+                               // Need to look at the cached annotation before going to fetch it again
+                               Field annotationCachingField = shadow.getEnclosingClass().getAnnotationCachingField(shadow, toType, isWithin);
+
+                               // Basic idea here is to check if the cached field is null, if it is then initialize it, otherwise use it
+                               il.append(fact.createGetStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation));
+                               il.append(InstructionConstants.DUP);
+                               InstructionBranch ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null);
+                               il.append(ifNonNull);
+                               il.append(InstructionConstants.POP);
+                               il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
+
+                               il.append(fact.createConstant(member.getName()));
+                               buildArray(il, fact, jlClass, paramTypes, 1);
+                               // OPTIMIZE cache result of getDeclaredMethod?
+                               il.append(fact.createInvoke("java/lang/Class", "getDeclaredMethod", jlrMethod,
+                                               new Type[] { jlString, jlClassArray }, Constants.INVOKEVIRTUAL));
+//                             il.append(pushConstant);// fact.createConstant(new ObjectType(toType.getName())));
+                               il.append(fact.createInvoke("java/lang/reflect/Method", "getParameterAnnotations", jlaAnnotationArrayArray, null, Constants.INVOKEVIRTUAL));
+                               il.append(fact.createConstant(parameterNumber));
+                               il.append(InstructionConstants.AALOAD);
+                               il.append(fact.createConstant(annotationOnParameterNumber));
+                               il.append(InstructionConstants.AALOAD);
+                               il.append(InstructionConstants.DUP);
+                               // Could loop over the set of annotations or we could 'guess' the right one?
+                               
+                               il.append(fact.createPutStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation));
+                               InstructionHandle ifNullElse = il.append(InstructionConstants.NOP);
+                               ifNonNull.setTarget(ifNullElse);
+
+                       } else { // init/preinit/ctor-call/ctor-exec
+                               il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
+                               buildArray(il, fact, jlClass, paramTypes, 1);
+                               Type jlrCtor = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_REFLECT_CONSTRUCTOR);
+                               // OPTIMIZE cache result of getDeclaredConstructor and getAnnotation? Might be able to use it again if someone else
+                               // needs the same annotations?
+                               il.append(fact.createInvoke("java/lang/Class", "getDeclaredConstructor", jlrCtor, new Type[] { jlClassArray },
+                                               Constants.INVOKEVIRTUAL));
+                               il.append(pushConstant);
+                               il.append(fact.createInvoke("java/lang/reflect/Constructor", "getAnnotation", jlaAnnotation,
+                                               new Type[] { jlClass }, Constants.INVOKEVIRTUAL));
+                       }
+               } else {
+                       throw new RuntimeException("Don't understand this kind " + kind);
+               }
+               il.append(Utility.createConversion(fact, jlaAnnotation, BcelWorld.makeBcelType(toType)));
+               return il;
+       }
+
+       private void buildArray(InstructionList il, InstructionFactory fact, Type arrayElementType, Type[] arrayEntries, int dim) {
+               il.append(fact.createConstant(Integer.valueOf(arrayEntries == null ? 0 : arrayEntries.length)));
+               il.append(fact.createNewArray(arrayElementType, (short) dim));
+               if (arrayEntries == null) {
+                       return;
+               }
+               for (int i = 0; i < arrayEntries.length; i++) {
+                       il.append(InstructionFactory.createDup(1));
+                       il.append(fact.createConstant(Integer.valueOf(i)));
+                       switch (arrayEntries[i].getType()) {
+                       case Constants.T_ARRAY:
+                               il.append(fact.createConstant(new ObjectType(arrayEntries[i].getSignature()))); // FIXME should be getName() and not
+                               // getSignature()?
+                               break;
+                       case Constants.T_BOOLEAN:
+                               il.append(fact.createGetStatic("java/lang/Boolean", "TYPE", arrayElementType));
+                               break;
+                       case Constants.T_BYTE:
+                               il.append(fact.createGetStatic("java/lang/Byte", "TYPE", arrayElementType));
+                               break;
+                       case Constants.T_CHAR:
+                               il.append(fact.createGetStatic("java/lang/Character", "TYPE", arrayElementType));
+                               break;
+                       case Constants.T_INT:
+                               il.append(fact.createGetStatic("java/lang/Integer", "TYPE", arrayElementType));
+                               break;
+                       case Constants.T_LONG:
+                               il.append(fact.createGetStatic("java/lang/Long", "TYPE", arrayElementType));
+                               break;
+                       case Constants.T_DOUBLE:
+                               il.append(fact.createGetStatic("java/lang/Double", "TYPE", arrayElementType));
+                               break;
+                       case Constants.T_FLOAT:
+                               il.append(fact.createGetStatic("java/lang/Float", "TYPE", arrayElementType));
+                               break;
+                       case Constants.T_SHORT:
+                               il.append(fact.createGetStatic("java/lang/Short", "TYPE", arrayElementType));
+                               break;
+                       default:
+                               il.append(fact.createConstant(arrayEntries[i]));
+                       }
+                       il.append(InstructionConstants.AASTORE);
+               }
+       }
+
+       @Override
+       public void appendLoad(InstructionList il, InstructionFactory fact) {
+               il.append(createLoadInstructions(getType(), fact));
+       }
+
+       @Override
+       public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) {
+               il.append(createLoadInstructions(toType, fact));
+       }
+
+       @Override
+       public void insertLoad(InstructionList il, InstructionFactory fact) {
+               il.insert(createLoadInstructions(getType(), fact));
+       }
+
+       /**
+        * Return an object that can access a particular field of this annotation.
+        * 
+        * @param valueType The type from the annotation that is of interest
+        * @param the formal name expressed in the pointcut, can be used to disambiguate
+        * @return a variable that represents access to that annotation field
+        */
+       @Override
+       public Var getAccessorForValue(ResolvedType valueType, String formalName) {
+               throw new IllegalStateException("Not supported for parameter annotations");
+       }
+}
index a978d9605da63726478441e999048519df1ab988..5de589f15afe3a3910860a1e26168cffafa7d6f9 100644 (file)
@@ -26,6 +26,7 @@ import org.aspectj.apache.bcel.classfile.Attribute;
 import org.aspectj.apache.bcel.classfile.JavaClass;
 import org.aspectj.apache.bcel.classfile.LocalVariable;
 import org.aspectj.apache.bcel.classfile.LocalVariableTable;
+import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
 import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository;
 import org.aspectj.apache.bcel.util.Repository;
 import org.aspectj.weaver.AnnotationAJ;
@@ -321,8 +322,7 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
                // here we really want both the runtime visible AND the class visible
                // annotations
                // so we bail out to Bcel and then chuck away the JavaClass so that we
-               // don't hog
-               // memory.
+               // don't hog memory.
                try {
                        JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
                        org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
@@ -386,5 +386,72 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
                }
                return result;
        }
+       
+       public Object getParamAnnotation(Member onMember, int argsIndex, int paramAnnoIndex) {
+               if (!(onMember instanceof AccessibleObject))
+                       return null;
+               // here we really want both the runtime visible AND the class visible
+               // annotations so we bail out to Bcel and then chuck away the JavaClass so that we
+               // don't hog memory.
+//             try {
+//                     JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
+//                     org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
+//                     if (onMember instanceof Method) {
+//                             org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
+//                             if (bcelMethod == null) {
+//                                     // pr220430
+//                                     // System.err.println(
+//                                     // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
+//                                     // + onMember.getName()+"' in class '"+jc.getClassName()+"'");
+//                             } else {
+//                                     anns = bcelMethod.getParameterAnnotations();
+//                             }
+//                     } else if (onMember instanceof Constructor) {
+//                             org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
+//                             anns = bcelCons.getParameterAnnotations();
+//                     } else if (onMember instanceof Field) {
+//                             // anns = null;
+//                     }
+//                     // the answer is cached and we don't want to hold on to memory
+//                     bcelRepository.clear();
+//                     if (anns == null)
+//                             return null;
+//                     
+//                     if (argsIndex>=anns.length) {
+//                             return null;
+//                     }
+//                     AnnotationGen[] parameterAnnotationsOnParticularArg = anns[argsIndex];
+//                     if (parameterAnnotationsOnParticularArg==null || paramAnnoIndex>=parameterAnnotationsOnParticularArg.length) {
+//                             return null;
+//                     }
+//                     AnnotationGen parameterAnnotation = parameterAnnotationsOnParticularArg[paramAnnoIndex];
+////                   if (parameterAnnotation.getTypeSignature().equals(ofType.getSignature())) {
+//                             return new BcelAnnotation(parameterAnnotation, world);
+////                   } else {
+////                           return null;
+////                   }
+//             } catch (ClassNotFoundException cnfEx) {
+//                     // just use reflection then
+//             }
+
+               // reflection...
+               AccessibleObject ao = (AccessibleObject) onMember;
+               Annotation[][] anns = null;
+               if (onMember instanceof Method) {
+                       anns = ((Method) ao).getParameterAnnotations();
+               } else if (onMember instanceof Constructor) {
+                       anns = ((Constructor) ao).getParameterAnnotations();
+               } else if (onMember instanceof Field) {
+                       // anns = null;
+               }
+               if (anns == null || argsIndex>=anns.length) {
+                       return null;
+               }
+               Annotation[] parameterAnnotationsOnParticularArg = anns[argsIndex];
+               if (parameterAnnotationsOnParticularArg==null || paramAnnoIndex>=parameterAnnotationsOnParticularArg.length) {
+                       return null;
+               }
+               return parameterAnnotationsOnParticularArg[paramAnnoIndex];
+       }
 
 }
diff --git a/weaver5/java5-src/org/aspectj/weaver/reflect/ReflectiveAnnotationAJ.java b/weaver5/java5-src/org/aspectj/weaver/reflect/ReflectiveAnnotationAJ.java
new file mode 100644 (file)
index 0000000..0b486b7
--- /dev/null
@@ -0,0 +1,103 @@
+/* *******************************************************************
+ * Copyright (c) 2016 Contributors.
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Andy Clement                      Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+import org.aspectj.weaver.AnnotationAJ;
+import org.aspectj.weaver.ResolvedType;
+
+/**
+ * An AnnotationAJ that wraps a java.lang.reflect Annotation.
+ *
+ * @author Andy Clement
+ */
+public class ReflectiveAnnotationAJ implements AnnotationAJ {
+       
+       private Annotation anno;
+
+       public ReflectiveAnnotationAJ(Annotation anno) {
+               this.anno = anno;
+       }
+
+       public String getTypeSignature() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public String getTypeName() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public ResolvedType getType() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public boolean allowedOnAnnotationType() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public boolean allowedOnField() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public boolean allowedOnRegularType() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public Set<String> getTargets() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public boolean hasNamedValue(String name) {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public boolean hasNameValuePair(String name, String value) {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public String getValidTargets() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public String stringify() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public boolean specifiesTarget() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public boolean isRuntimeVisible() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public String getStringFormOfValue(String name) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+}
index 9b155df3e4a7687e8395cdf87de02f60227b7bce..e3a4981c125c7b05b267bd3279909087e2cbef3d 100644 (file)
@@ -11,6 +11,7 @@
  * ******************************************************************/
 package org.aspectj.weaver.tools;
 
+import java.lang.annotation.Annotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Method;
@@ -63,6 +64,9 @@ public class Java15PointcutExpressionTest extends TestCase {
        private Method b;
        private Method c;
        private Method d;
+       private Method e;
+       private Method f;
+       
        
        /**
         * Parse some expressions and ensure we capture the parameter annotations and parameter type annotations correctly.
@@ -508,6 +512,43 @@ public class Java15PointcutExpressionTest extends TestCase {
                assertEquals("annotation on B",bAnnotation,jp2.getParameterBindings()[1].getBinding());         
        }
        
+       public void testAtArgsWithParamBinding() throws Exception {
+               // B class contains: public void e(@MyAnnotation A anA, B aB) {}
+               PointcutParameter pp = parser.createPointcutParameter("a", MyAnnotation.class);
+               PointcutExpression atArgs = parser.parsePointcutExpression("@args(a (*),..)",A.class,new PointcutParameter[] {pp});
+               ShadowMatch shadowMatch = atArgs.matchesMethodExecution(e);
+               assertTrue(shadowMatch.alwaysMatches());
+               JoinPointMatch jpm = shadowMatch.matchesJoinPoint(new B(), new B(), new Object[] {new A(), new B()});
+               assertEquals(1,jpm.getParameterBindings().length);
+               MyAnnotation expectedAnnotation = (MyAnnotation)B.class.getDeclaredMethod("e", A.class,B.class).getParameterAnnotations()[0][0];
+               Object boundAnnotation = jpm.getParameterBindings()[0].getBinding();
+               assertEquals(expectedAnnotation,boundAnnotation);
+               
+               pp = parser.createPointcutParameter("a", MyAnnotationWithValue.class);
+               PointcutParameter pp2 = parser.createPointcutParameter("b", MyAnnotationWithValue.class);
+               atArgs = parser.parsePointcutExpression("@args(a,b)",A.class,new PointcutParameter[] {pp,pp2});
+               shadowMatch = atArgs.matchesMethodExecution(f);
+               assertTrue(shadowMatch.alwaysMatches());
+               jpm = shadowMatch.matchesJoinPoint(new B(), new B(), new Object[] {new A(), new B()});
+               assertEquals(2,jpm.getParameterBindings().length);
+               MyAnnotationWithValue expectedAnnotation1 = (MyAnnotationWithValue)B.class.getDeclaredMethod("e", A.class,B.class).getParameterAnnotations()[0][0];
+               MyAnnotationWithValue expectedAnnotation2 = (MyAnnotationWithValue)B.class.getDeclaredMethod("e", A.class,B.class).getParameterAnnotations()[1][0];
+               Object boundAnnotation1 = jpm.getParameterBindings()[0].getBinding();
+               assertEquals(expectedAnnotation1,boundAnnotation1);
+               Object boundAnnotation2 = jpm.getParameterBindings()[1].getBinding();
+               assertEquals(expectedAnnotation2,boundAnnotation1);
+               
+//             
+//             atArgs = parser.parsePointcutExpression("@args(a,b)",A.class,new PointcutParameter[] {p1,p2});
+//             sMatch2 = atArgs.matchesMethodExecution(c);
+//             assertTrue("maybe matches C",sMatch2.maybeMatches());
+//             jp2 = sMatch2.matchesJoinPoint(new B(), new B(), new Object[] {new B(),new B()});
+//             assertTrue("matches",jp2.matches());                                                    
+//             assertEquals(2,jp2.getParameterBindings().length);
+//             assertEquals("annotation on B",bAnnotation,jp2.getParameterBindings()[0].getBinding());
+//             assertEquals("annotation on B",bAnnotation,jp2.getParameterBindings()[1].getBinding());         
+       }
+       
        public void testAtWithin() {
                PointcutExpression atWithin = parser.parsePointcutExpression("@within(org.aspectj.weaver.tools.Java15PointcutExpressionTest.MyAnnotation)");
                ShadowMatch sMatch1 = atWithin.matchesMethodExecution(a);
@@ -670,11 +711,18 @@ public class Java15PointcutExpressionTest extends TestCase {
                b = B.class.getMethod("b");
                c = B.class.getMethod("c",new Class[] {A.class,B.class});
                d = B.class.getMethod("d",new Class[] {A.class,A.class});
+               e = B.class.getMethod("e", new Class[] {A.class, B.class});
+               f = B.class.getMethod("f", A.class, B.class);
        }
 
        @Retention(RetentionPolicy.RUNTIME)
        private @interface MyAnnotation {}
-       
+
+       @Retention(RetentionPolicy.RUNTIME)
+       private @interface MyAnnotationWithValue {
+               String value();
+       }
+
        private @interface MyClassFileRetentionAnnotation {}
        
        private static class A {
@@ -687,6 +735,10 @@ public class Java15PointcutExpressionTest extends TestCase {
                public void c(A anA, B aB) {}
                
                public void d(A anA, A anotherA) {}
+               
+               public void e(@MyAnnotation A anA, B aB) {}
+               
+               public void f(@MyAnnotationWithValue("abc") A anA, @MyAnnotationWithValue("def") B aB) {}
        }
        
        private static class C {