diff options
author | Andy Clement <aclement@pivotal.io> | 2016-12-02 10:32:17 -0800 |
---|---|---|
committer | Andy Clement <aclement@pivotal.io> | 2016-12-02 10:32:17 -0800 |
commit | d10618d25a9e995ffeb8080b3b9468ad241a163c (patch) | |
tree | e6d7392533635926c055048deb040e778fe92e20 | |
parent | b6f2b6337fbaf95b78c20862cd90f0e027509531 (diff) | |
download | aspectj-paramAnnotationBinding.tar.gz aspectj-paramAnnotationBinding.zip |
259416: preliminary workparamAnnotationBinding
32 files changed, 809 insertions, 54 deletions
diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/Member.java b/org.aspectj.matcher/src/org/aspectj/weaver/Member.java index 8134e8df2..f3a11ff9b 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/Member.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/Member.java @@ -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); diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/MemberImpl.java b/org.aspectj.matcher/src/org/aspectj/weaver/MemberImpl.java index fbf497ed2..89e0e39e1 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/MemberImpl.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/MemberImpl.java @@ -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. diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/Shadow.java b/org.aspectj.matcher/src/org/aspectj/weaver/Shadow.java index 587d19c15..07c62aaa6 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/Shadow.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/Shadow.java @@ -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(); /** diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AnnotationPatternList.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AnnotationPatternList.java index 0b93b48d1..af8827202 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AnnotationPatternList.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AnnotationPatternList.java @@ -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; } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java index db612b8cd..9eeaf5b2c 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java @@ -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++; } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java index 142f6155e..f8e27ad2e 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java @@ -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; } } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java index 772e8f6ca..0ee8a3369 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java @@ -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; } } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java index 106376aad..8f3068ac1 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java @@ -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; } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/AnnotationFinder.java b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/AnnotationFinder.java index 7efeac9ae..5e1957f20 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/AnnotationFinder.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/AnnotationFinder.java @@ -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); } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionShadow.java b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionShadow.java index 0c6277e59..4e6e0cef8 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionShadow.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionShadow.java @@ -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) diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionVar.java b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionVar.java index 59876a737..542d36cad 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionVar.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/ReflectionVar.java @@ -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); diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java index c151b228e..0594a8ff6 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/reflect/StandardShadow.java @@ -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 index 000000000..e69de29bb --- /dev/null +++ b/tests/bugs1810/259416/Caveats diff --git a/tests/bugs1810/259416/ColouredAnnotation.class b/tests/bugs1810/259416/ColouredAnnotation.class Binary files differnew file mode 100644 index 000000000..ff8b19572 --- /dev/null +++ b/tests/bugs1810/259416/ColouredAnnotation.class diff --git a/tests/bugs1810/259416/ColouredAnnotation.java b/tests/bugs1810/259416/ColouredAnnotation.java new file mode 100644 index 000000000..1886a2f03 --- /dev/null +++ b/tests/bugs1810/259416/ColouredAnnotation.java @@ -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 index 000000000..e69de29bb --- /dev/null +++ b/tests/bugs1810/259416/Creating diff --git a/tests/bugs1810/259416/Downloading b/tests/bugs1810/259416/Downloading new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/bugs1810/259416/Downloading diff --git a/tests/bugs1810/259416/Filler.java b/tests/bugs1810/259416/Filler.java new file mode 100644 index 000000000..dc5592b41 --- /dev/null +++ b/tests/bugs1810/259416/Filler.java @@ -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 Binary files differnew file mode 100644 index 000000000..737e3b6bb --- /dev/null +++ b/tests/bugs1810/259416/RGB.class diff --git a/tests/bugs1810/259416/RGB.java b/tests/bugs1810/259416/RGB.java new file mode 100644 index 000000000..04d4e9474 --- /dev/null +++ b/tests/bugs1810/259416/RGB.java @@ -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 index 000000000..e69de29bb --- /dev/null +++ b/tests/bugs1810/259416/Tapping diff --git a/tests/bugs1810/259416/Test1.java b/tests/bugs1810/259416/Test1.java new file mode 100644 index 000000000..e4961f039 --- /dev/null +++ b/tests/bugs1810/259416/Test1.java @@ -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 index 000000000..a2a026dbc --- /dev/null +++ b/tests/bugs1810/259416/Test2.java @@ -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 index 000000000..49744de78 --- /dev/null +++ b/tests/bugs1810/259416/Test3.java @@ -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 index 000000000..92324f883 --- /dev/null +++ b/tests/bugs1810/259416/Test4.java @@ -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); + } +} diff --git a/tests/src/org/aspectj/systemtest/ajc1810/Ajc1810Tests.java b/tests/src/org/aspectj/systemtest/ajc1810/Ajc1810Tests.java index 3cae1378c..36232a91d 100644 --- a/tests/src/org/aspectj/systemtest/ajc1810/Ajc1810Tests.java +++ b/tests/src/org/aspectj/systemtest/ajc1810/Ajc1810Tests.java @@ -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"); } diff --git a/tests/src/org/aspectj/systemtest/ajc1810/ajc1810.xml b/tests/src/org/aspectj/systemtest/ajc1810/ajc1810.xml index 7485c1c20..75edcbc5e 100644 --- a/tests/src/org/aspectj/systemtest/ajc1810/ajc1810.xml +++ b/tests/src/org/aspectj/systemtest/ajc1810/ajc1810.xml @@ -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"> diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index 10fdbd05c..914e99697 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -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; @@ -953,6 +954,12 @@ public class BcelShadow extends Shadow { } @Override + public Var getArgParamAnnotationVar(int parameterIndex, UnresolvedType forAnnotationType) { + initializeKindedAnnotationVars(); + return paramAnnoVars[parameterIndex].get(forAnnotationType); + } + + @Override public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) { initializeWithinAnnotationVars(); return withinAnnotationVars.get(forAnnotationType); @@ -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 index 000000000..e3cebc37f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/ParamAnnotationAccessVar.java @@ -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"); + } +} diff --git a/weaver5/java5-src/org/aspectj/weaver/reflect/Java15AnnotationFinder.java b/weaver5/java5-src/org/aspectj/weaver/reflect/Java15AnnotationFinder.java index a978d9605..5de589f15 100644 --- a/weaver5/java5-src/org/aspectj/weaver/reflect/Java15AnnotationFinder.java +++ b/weaver5/java5-src/org/aspectj/weaver/reflect/Java15AnnotationFinder.java @@ -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 index 000000000..0b486b7ed --- /dev/null +++ b/weaver5/java5-src/org/aspectj/weaver/reflect/ReflectiveAnnotationAJ.java @@ -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; + } + +} diff --git a/weaver5/java5-testsrc/org/aspectj/weaver/tools/Java15PointcutExpressionTest.java b/weaver5/java5-testsrc/org/aspectj/weaver/tools/Java15PointcutExpressionTest.java index 9b155df3e..e3a4981c1 100644 --- a/weaver5/java5-testsrc/org/aspectj/weaver/tools/Java15PointcutExpressionTest.java +++ b/weaver5/java5-testsrc/org/aspectj/weaver/tools/Java15PointcutExpressionTest.java @@ -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 { |