From 96e92b6024e770a539a3040976e54eef2ee6d8f7 Mon Sep 17 00:00:00 2001 From: acolyer Date: Thu, 9 Dec 2004 16:27:56 +0000 Subject: [PATCH] more @this @target fixes and tests --- .../compiler/lookup/EclipseSourceType.java | 8 + .../thisOrtarget/BindingLimitation.aj | 10 ++ .../thisOrtarget/NotRuntimeRetention.aj | 18 +++ .../thisOrtarget/ThisOrTargetTests.aj | 16 +- .../ajc150/AnnotationRuntimeTests.java | 48 ++++++ .../src/org/aspectj/weaver/ResolvedTypeX.java | 11 ++ weaver/src/org/aspectj/weaver/TypeX.java | 11 +- .../org/aspectj/weaver/WeaverMessages.java | 1 + .../org/aspectj/weaver/ast/HasAnnotation.java | 55 +++++++ .../org/aspectj/weaver/ast/ITestVisitor.java | 1 + weaver/src/org/aspectj/weaver/ast/Test.java | 4 + .../aspectj/weaver/bcel/BcelObjectType.java | 24 +++ .../org/aspectj/weaver/bcel/BcelRenderer.java | 24 +++ .../patterns/AnnotationTypePattern.java | 2 +- .../BindingAnnotationTypePattern.java | 11 ++ .../weaver/patterns/PatternParser.java | 2 +- .../org/aspectj/weaver/patterns/Pointcut.java | 2 + .../aspectj/weaver/patterns/PointcutImpl.java | 51 +++++++ .../ThisOrTargetAnnotationPointcut.java | 137 +++++++++++++++--- .../aspectj/weaver/weaver-messages.properties | 2 +- 20 files changed, 403 insertions(+), 35 deletions(-) create mode 100644 tests/java5/annotations/thisOrtarget/BindingLimitation.aj create mode 100644 tests/java5/annotations/thisOrtarget/NotRuntimeRetention.aj create mode 100644 tests/src/org/aspectj/systemtest/ajc150/AnnotationRuntimeTests.java create mode 100644 weaver/src/org/aspectj/weaver/ast/HasAnnotation.java create mode 100644 weaver/src/org/aspectj/weaver/patterns/PointcutImpl.java diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java index 7a5207324..7fbcd12cb 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java @@ -221,6 +221,14 @@ public class EclipseSourceType extends ResolvedTypeX.ConcreteName { return (binding.getAccessFlags() & ACC_ANNOTATION)!=0; } + public boolean isAnnotationWithRuntimeRetention() { + if (!isAnnotation()) { + return false; + } else { + throw new RuntimeException("How to implement this? Needs to ask eclipse!"); + } + } + public boolean hasAnnotation(TypeX ofType) { throw new RuntimeException("How to implement this? Needs to ask eclipse!"); } diff --git a/tests/java5/annotations/thisOrtarget/BindingLimitation.aj b/tests/java5/annotations/thisOrtarget/BindingLimitation.aj new file mode 100644 index 000000000..1ed24c99f --- /dev/null +++ b/tests/java5/annotations/thisOrtarget/BindingLimitation.aj @@ -0,0 +1,10 @@ +public aspect BindingLimitation { + + pointcut doSomethingExecution() : execution(* doSomething()); + pointcut doSomethingCall() : call(* doSomething()); + + after(MyAnnotation ann) returning : @target(ann) && doSomethingCall() { + // should be compile time error (limitation) + } + +} \ No newline at end of file diff --git a/tests/java5/annotations/thisOrtarget/NotRuntimeRetention.aj b/tests/java5/annotations/thisOrtarget/NotRuntimeRetention.aj new file mode 100644 index 000000000..ea38a52c4 --- /dev/null +++ b/tests/java5/annotations/thisOrtarget/NotRuntimeRetention.aj @@ -0,0 +1,18 @@ +public aspect NotRuntimeRetention { + + pointcut doSomethingExecution() : execution(* doSomething()); + pointcut doSomethingCall() : call(* doSomething()); + + // CE L7 + before() : doSomethingExecution() && @this(@MyClassRetentionAnnotation) { + // should be compile-time error! + System.out.println("How did I get here?"); + } + + // CE L13 + after() returning : doSomethingCall() && @target(@MyClassRetentionAnnotation) { + // should be compile-time error! + System.out.println("How did I get here?"); + } + +} \ No newline at end of file diff --git a/tests/java5/annotations/thisOrtarget/ThisOrTargetTests.aj b/tests/java5/annotations/thisOrtarget/ThisOrTargetTests.aj index c642da9aa..cc5ab5cd0 100644 --- a/tests/java5/annotations/thisOrtarget/ThisOrTargetTests.aj +++ b/tests/java5/annotations/thisOrtarget/ThisOrTargetTests.aj @@ -12,10 +12,6 @@ public aspect ThisOrTargetTests { System.out.println("@this(@MyAnnotation): " + thisJoinPointStaticPart); } - before() : doSomethingExecution() && @this(@MyClassRetentionAnnotation) { - // should be compile-time error! - } - before() : doSomethingExecution() && @this(@MyInheritableAnnotation) { // should match: // c.doSomething() @@ -24,17 +20,13 @@ public aspect ThisOrTargetTests { System.out.println("@this(@MyInheritableAnnotation): " + thisJoinPointStaticPart); } - after() returning : doSomthingCall() && @target(@MyAnnotation) { + after() returning : doSomethingCall() && @target(@MyAnnotation) { // should match: // b.doSomething(), reallyB.doSomething() [with test], // c.doSomething() System.out.println("@target(@MyAnnotation): " + thisJoinPointStaticPart); } - after() returning : doSomethingCall() && @target(@MyClassRetentionAnnotation) { - // should be compile-time error! - } - after() returning : doSomethingCall() && @target(@MyInheritableAnnotation) { // should match: // c.doSomething() @@ -42,9 +34,5 @@ public aspect ThisOrTargetTests { // reallyD.doSomething() System.out.println("@target(@MyInheritableAnnotation): " + thisJoinPointStaticPart); } - - after(MyAnnotation ann) returning : @target(ann) { - // should be compile time error (limitation) - } - + } \ No newline at end of file diff --git a/tests/src/org/aspectj/systemtest/ajc150/AnnotationRuntimeTests.java b/tests/src/org/aspectj/systemtest/ajc150/AnnotationRuntimeTests.java new file mode 100644 index 000000000..06b54d483 --- /dev/null +++ b/tests/src/org/aspectj/systemtest/ajc150/AnnotationRuntimeTests.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.systemtest.ajc150; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.tools.ajc.CompilationResult; + +/** +* Tests for @this, @target, @args +*/ +public class AnnotationRuntimeTests extends TestUtils { + + protected void setUp() throws Exception { + super.setUp(); + baseDir = new File("../tests/java5/annotations/thisOrtarget"); + } + + public void test001_NoBinding() { + CompilationResult cR = binaryWeave("TestingAnnotations.jar","BindingLimitation.aj",1,0); + List errors = cR.getErrorMessages(); + assertTrue("Binding not supported",errors.get(0).toString().startsWith("error Binding not supported")); + } + + public void test002_MustHaveRuntimeRetention() { + CompilationResult cR = binaryWeave("TestingAnnotations.jar","NotRuntimeRetention.aj",2,0); + List errors = new ArrayList(); + errors.add(new Message(7,"Annotation type MyClassRetentionAnnotation does not have runtime retention")); + errors.add(new Message(13,"Annotation type MyClassRetentionAnnotation does not have runtime retention")); + + MessageSpec messageSpec = new MessageSpec(new ArrayList(), errors); + assertMessages(cR, messageSpec); + } + + public void test003_InheritableOrNot() { + CompilationResult cR = binaryWeave("TestingAnnotations.jar","ThisOrTargetTests.aj",0,0); + } +} diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java index 7b9a60174..f324affae 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java @@ -469,6 +469,12 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { return false; } + /** + * Note: Only overridden by Name subtype. + */ + public boolean isAnnotationWithRuntimeRetention() { + return false; + } public boolean isSynthetic() { return signature.indexOf("$ajc") != -1; @@ -579,6 +585,10 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { public boolean isAnnotation() { return delegate.isAnnotation(); } + + public boolean isAnnotationWithRuntimeRetention() { + return delegate.isAnnotationWithRuntimeRetention(); + } public final boolean needsNoConversionFrom(TypeX o) { return isAssignableFrom(o); @@ -724,6 +734,7 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { public abstract boolean isInterface(); public abstract boolean isEnum(); public abstract boolean isAnnotation(); + public abstract boolean isAnnotationWithRuntimeRetention(); public abstract boolean hasAnnotation(TypeX ofType); public abstract ResolvedTypeX[] getAnnotationTypes(); diff --git a/weaver/src/org/aspectj/weaver/TypeX.java b/weaver/src/org/aspectj/weaver/TypeX.java index 2cc7528f3..6a44d338c 100644 --- a/weaver/src/org/aspectj/weaver/TypeX.java +++ b/weaver/src/org/aspectj/weaver/TypeX.java @@ -427,6 +427,13 @@ public class TypeX implements AnnotatedElement { public final boolean isAnnotation(World world) { return world.resolve(this).isAnnotation(); } + + /** + * Determine if this class represents an annotation type that has runtime retention + */ + public final boolean isAnnotationWithRuntimeRetention(World world) { + return world.resolve(this).isAnnotationWithRuntimeRetention(); + } /** @@ -572,7 +579,9 @@ public class TypeX implements AnnotatedElement { public static final TypeX SERIALIZABLE = forSignature("Ljava/io/Serializable;"); public static final TypeX THROWABLE = forSignature("Ljava/lang/Throwable;"); public static final TypeX RUNTIME_EXCEPTION = forSignature("Ljava/lang/RuntimeException;"); - public static final TypeX ERROR = forSignature("Ljava/lang/Error;"); + public static final TypeX ERROR = forSignature("Ljava/lang/Error;"); + public static final TypeX AT_INHERITED = forSignature("Ljava/lang/annotation/Inherited;"); + public static final TypeX AT_RETENTION = forSignature("Ljava/lang/annotation/Retention;"); // ---- helpers diff --git a/weaver/src/org/aspectj/weaver/WeaverMessages.java b/weaver/src/org/aspectj/weaver/WeaverMessages.java index 9bcd3e63c..4cb4da5b7 100644 --- a/weaver/src/org/aspectj/weaver/WeaverMessages.java +++ b/weaver/src/org/aspectj/weaver/WeaverMessages.java @@ -110,6 +110,7 @@ public class WeaverMessages { public static final String ITDM_ON_ANNOTATION_NOT_ALLOWED = "itdmOnAnnotationNotAllowed"; public static final String ITDF_ON_ANNOTATION_NOT_ALLOWED = "itdfOnAnnotationNotAllowed"; public static final String REFERENCE_TO_NON_ANNOTATION_TYPE = "referenceToNonAnnotationType"; + public static final String BINDING_NON_RUNTIME_RETENTION_ANNOTATION = "bindingNonRuntimeRetentionAnnotation"; public static String format(String key) { return bundle.getString(key); diff --git a/weaver/src/org/aspectj/weaver/ast/HasAnnotation.java b/weaver/src/org/aspectj/weaver/ast/HasAnnotation.java new file mode 100644 index 000000000..4bdeecb7c --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/HasAnnotation.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.TypeX; + +public class HasAnnotation extends Test { + + private Var v; + private ResolvedTypeX annType; + + public HasAnnotation(Var v, ResolvedTypeX annType) { + super(); + this.v = v; + this.annType = annType; + } + + /* (non-Javadoc) + * @see org.aspectj.weaver.ast.Test#accept(org.aspectj.weaver.ast.ITestVisitor) + */ + public void accept(ITestVisitor v) { + v.visit(this); + } + + public String toString() { + return "(" + v + " has annotation @" + annType + ")"; + } + + public boolean equals(Object other) { + if (other instanceof HasAnnotation) { + HasAnnotation o = (HasAnnotation) other; + return o.v.equals(v) && o.annType.equals(annType); + } else { + return false; + } + } + + public Var getVar() { + return v; + } + + public TypeX getAnnotationType() { + return annType; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/ITestVisitor.java b/weaver/src/org/aspectj/weaver/ast/ITestVisitor.java index 4147afbd8..67035e6dc 100644 --- a/weaver/src/org/aspectj/weaver/ast/ITestVisitor.java +++ b/weaver/src/org/aspectj/weaver/ast/ITestVisitor.java @@ -23,5 +23,6 @@ public interface ITestVisitor { void visit(Literal literal); void visit(Call call); void visit(FieldGetCall fieldGetCall); + void visit(HasAnnotation hasAnnotation); } diff --git a/weaver/src/org/aspectj/weaver/ast/Test.java b/weaver/src/org/aspectj/weaver/ast/Test.java index b714ccb82..73d18dd84 100644 --- a/weaver/src/org/aspectj/weaver/ast/Test.java +++ b/weaver/src/org/aspectj/weaver/ast/Test.java @@ -81,6 +81,10 @@ public abstract class Test extends ASTNode { return e; } + public static Test makeHasAnnotation(Var v, ResolvedTypeX annTy) { + return new HasAnnotation(v,annTy); + } + public static Test makeCall(Member m, Expr[] args) { return new Call(m, args); } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java index ce8a253b2..9ccd7ad6d 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java @@ -25,6 +25,8 @@ import org.aspectj.apache.bcel.classfile.Field; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.Method; import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.classfile.annotation.ElementValue; import org.aspectj.bridge.ISourceLocation; import org.aspectj.weaver.AjAttribute; import org.aspectj.weaver.BCException; @@ -293,6 +295,28 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { return javaClass.isAnnotation(); } + public boolean isAnnotationWithRuntimeRetention() { + if (!isAnnotation()) { + return false; + } else { + Annotation[] annotationsOnThisType = javaClass.getAnnotations(); + for (int i = 0; i < annotationsOnThisType.length; i++) { + Annotation a = annotationsOnThisType[i]; + if (a.getTypeName().equals(TypeX.AT_RETENTION.getName())) { + List values = a.getValues(); + boolean isRuntime = false; + for (Iterator it = values.iterator(); it.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) it.next(); + ElementValue v = element.getValue(); + isRuntime = v.stringifyValue().equals("RUNTIME"); + } + return isRuntime; + } + } + } + return false; + } + public boolean isSynthetic() { return getResolvedTypeX().isSynthetic(); } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java b/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java index b2b50ca83..1c74a5229 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java @@ -17,16 +17,19 @@ import org.aspectj.apache.bcel.Constants; 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.LDC_W; import org.aspectj.apache.bcel.generic.ReferenceType; import org.aspectj.apache.bcel.generic.Type; import org.aspectj.weaver.BCException; import org.aspectj.weaver.Member; +import org.aspectj.weaver.TypeX; import org.aspectj.weaver.ast.And; import org.aspectj.weaver.ast.Call; import org.aspectj.weaver.ast.CallExpr; import org.aspectj.weaver.ast.Expr; import org.aspectj.weaver.ast.FieldGet; import org.aspectj.weaver.ast.FieldGetCall; +import org.aspectj.weaver.ast.HasAnnotation; import org.aspectj.weaver.ast.IExprVisitor; import org.aspectj.weaver.ast.ITestVisitor; import org.aspectj.weaver.ast.Instanceof; @@ -171,6 +174,27 @@ public class BcelRenderer implements ITestVisitor, IExprVisitor { i.getVar().accept(this); } + public void visit(HasAnnotation hasAnnotation) { + instructions.insert(createJumpBasedOnBooleanOnStack()); + // now insert the instructions that leave a boolean on the stack + // in Java: + // foo.class.isAnnotationPresent(annotationClass); + // in bytecode: + // load var onto the stack (done for us later) + // invokevirtual java/lang/Object.getClass:()Ljava/lang/Class + // ldc_w annotationClass + // invokevirtual java/lang/Class.isAnnotationPresent:(Ljava/lang/Class;)Z + Member getClass = Member.method(TypeX.OBJECT, 0, "getClass", "()Ljava/lang/Class;"); + instructions.insert(Utility.createInvoke(fact, world, getClass)); + // aload annotationClass + int annClassIndex = fact.getConstantPool().addClass(hasAnnotation.getAnnotationType().getSignature()); + instructions.insert(new LDC_W(annClassIndex)); + Member isAnnotationPresent = Member.method(TypeX.forName("Ljava/lang/Class"),0, + "isAnnotationPresent","(Ljava/lang/Class;)Z"); + instructions.insert(Utility.createInvoke(fact,world,isAnnotationPresent)); + hasAnnotation.getVar().accept(this); + } + private InstructionList createJumpBasedOnBooleanOnStack() { InstructionList il = new InstructionList(); if (sk == fk) { diff --git a/weaver/src/org/aspectj/weaver/patterns/AnnotationTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/AnnotationTypePattern.java index ad8eab5c8..60edc3f37 100644 --- a/weaver/src/org/aspectj/weaver/patterns/AnnotationTypePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/AnnotationTypePattern.java @@ -61,7 +61,7 @@ public abstract class AnnotationTypePattern extends PatternNode { byte key = s.readByte(); switch(key) { case EXACT: return ExactAnnotationTypePattern.read(s, context); -// case BINDING: return BindingAnnotationTypePattern.read(s, context); + case BINDING: return BindingAnnotationTypePattern.read(s, context); case NOT: return NotAnnotationTypePattern.read(s, context); case OR: return OrAnnotationTypePattern.read(s, context); case AND: return AndAnnotationTypePattern.read(s, context); diff --git a/weaver/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java index 1a369fccf..d6b632052 100644 --- a/weaver/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java @@ -55,6 +55,17 @@ public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern imp world.getMessageHandler().handleMessage(m); resolved = false; } + if (!annotationType.hasAnnotation(TypeX.AT_RETENTION)) { + // default is class visibility + IMessage m = MessageUtil.error( + WeaverMessages.format(WeaverMessages.BINDING_NON_RUNTIME_RETENTION_ANNOTATION,annotationType.getName()), + getSourceLocation()); + world.getMessageHandler().handleMessage(m); + resolved = false; + } else { + // TO DO... get the retention policy annotation, and check the value is + // RetentionPolicy.RUNTIME; + } return this; } diff --git a/weaver/src/org/aspectj/weaver/patterns/PatternParser.java b/weaver/src/org/aspectj/weaver/patterns/PatternParser.java index 1eab94f92..9b994deb8 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PatternParser.java +++ b/weaver/src/org/aspectj/weaver/patterns/PatternParser.java @@ -351,7 +351,7 @@ public class PatternParser { if (maybeEat(")")) { throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek()); } - AnnotationTypePattern type = parseAnnotationNameOrVarTypePattern(); + ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern(); eat(")"); return new ThisOrTargetAnnotationPointcut(kind.equals("this"),type); } diff --git a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java index e29b80c44..afd01ce86 100644 --- a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java @@ -127,6 +127,7 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression public static final byte ANNOTATION = 16; public static final byte ATWITHIN = 17; public static final byte ATWITHINCODE = 18; + public static final byte ATTHIS_OR_TARGET = 19; public static final byte NONE = 20; @@ -247,6 +248,7 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression case ANNOTATION: ret = AnnotationPointcut.read(s, context); break; case ATWITHIN: ret = WithinAnnotationPointcut.read(s, context); break; case ATWITHINCODE: ret = WithinCodeAnnotationPointcut.read(s, context); break; + case ATTHIS_OR_TARGET: ret = ThisOrTargetAnnotationPointcut.read(s, context); break; case NONE: ret = makeMatchesNothing(RESOLVED); break; default: throw new BCException("unknown kind: " + kind); diff --git a/weaver/src/org/aspectj/weaver/patterns/PointcutImpl.java b/weaver/src/org/aspectj/weaver/patterns/PointcutImpl.java new file mode 100644 index 000000000..839ae9344 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PointcutImpl.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.aspectj.weaver.patterns; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.JoinPoint.StaticPart; +import org.aspectj.lang.reflect.Pointcut; +import org.aspectj.util.FuzzyBoolean; + +/** + * Implementation of the reflective pointcut interface in org.aspectj.lang.reflect + * (not to be confused with the Pointcut class in this package, which itself should + * be considered part of the weaver implementation). + */ +public class PointcutImpl implements Pointcut { + + private String pointcutExpression; + private org.aspectj.weaver.patterns.Pointcut pointcut; + + public PointcutImpl(String pointcutExpression) { + this.pointcutExpression = pointcutExpression; + try { + pointcut = new PatternParser(pointcutExpression).parsePointcut(); + } catch (ParserException pEx) { + throw new IllegalArgumentException(pEx.getMessage()); + } + } + + /* (non-Javadoc) + * @see org.aspectj.lang.reflect.Pointcut#matches(org.aspectj.lang.JoinPoint, org.aspectj.lang.JoinPoint.StaticPart) + */ + public boolean matches(JoinPoint jp, StaticPart enclosingJoinPoint) { + return pointcut.match(jp,enclosingJoinPoint) == FuzzyBoolean.YES; + } + + /* (non-Javadoc) + * @see org.aspectj.lang.reflect.Pointcut#getPointcutExpression() + */ + public String getPointcutExpression() { + return pointcutExpression; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java index 7c1a30264..4b8686c27 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java @@ -9,14 +9,25 @@ * ******************************************************************/ package org.aspectj.weaver.patterns; +import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.bridge.Message; +import org.aspectj.bridge.MessageUtil; import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.Shadow; +import org.aspectj.weaver.ShadowMunger; +import org.aspectj.weaver.TypeX; +import org.aspectj.weaver.WeaverMessages; +import org.aspectj.weaver.ast.Literal; import org.aspectj.weaver.ast.Test; +import org.aspectj.weaver.ast.Var; /** * @author colyer @@ -27,31 +38,45 @@ import org.aspectj.weaver.ast.Test; public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut { private boolean isThis; - private AnnotationTypePattern type; + private ExactAnnotationTypePattern annotationTypePattern; + private ShadowMunger munger; /** * */ - public ThisOrTargetAnnotationPointcut(boolean isThis, AnnotationTypePattern type) { + public ThisOrTargetAnnotationPointcut(boolean isThis, ExactAnnotationTypePattern type) { super(); this.isThis = isThis; - this.type = type; + this.annotationTypePattern = type; } + public ThisOrTargetAnnotationPointcut(boolean isThis, ExactAnnotationTypePattern type, ShadowMunger munger) { + this(isThis,type); + this.munger = munger; + } + /* (non-Javadoc) * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo) */ public FuzzyBoolean fastMatch(FastMatchInfo info) { - // TODO Auto-generated method stub - return null; + return FuzzyBoolean.MAYBE; } /* (non-Javadoc) * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow) */ public FuzzyBoolean match(Shadow shadow) { - // TODO Auto-generated method stub - return null; + if (!couldMatch(shadow)) return FuzzyBoolean.NO; + TypeX annotationType = annotationTypePattern.annotationType; + annotationType = annotationType.resolve(shadow.getIWorld()); + if (annotationType.hasAnnotation(TypeX.AT_INHERITED)) { + // we can attempt to match now + ResolvedTypeX toMatchAgainst = + (isThis ? shadow.getThisType() : shadow.getTargetType() ).resolve(shadow.getIWorld()); + return FuzzyBoolean.fromBoolean(toMatchAgainst.hasAnnotation(annotationType)); + } + // else we can only do matching via a runtime test + return FuzzyBoolean.MAYBE; } public boolean isThis() { return isThis; } @@ -60,8 +85,17 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut { * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope, org.aspectj.weaver.patterns.Bindings) */ protected void resolveBindings(IScope scope, Bindings bindings) { - // TODO Auto-generated method stub - + annotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern.resolveBindings(scope,bindings,true); + // must be either a Var, or an annotation type pattern + // if annotationType does not have runtime retention, this is an error + ResolvedTypeX rAnnotationType = (ResolvedTypeX) annotationTypePattern.annotationType; + if (!(rAnnotationType.isAnnotationWithRuntimeRetention())) { + IMessage m = MessageUtil.error( + WeaverMessages.format(WeaverMessages.BINDING_NON_RUNTIME_RETENTION_ANNOTATION,rAnnotationType.getName()), + getSourceLocation()); + scope.getMessageHandler().handleMessage(m); + } + } /* (non-Javadoc) @@ -76,33 +110,102 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut { * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedTypeX, org.aspectj.weaver.IntMap) */ protected Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { - // TODO Auto-generated method stub - return null; + ExactAnnotationTypePattern newType = (ExactAnnotationTypePattern) annotationTypePattern.remapAdviceFormals(bindings); + Pointcut ret = new ThisOrTargetAnnotationPointcut(isThis, newType, bindings.getEnclosingAdvice()); + ret.copyLocationFrom(this); + return ret; } /* (non-Javadoc) * @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState) */ public Test findResidue(Shadow shadow, ExposedState state) { - // TODO Auto-generated method stub - return null; + if (!couldMatch(shadow)) return Literal.FALSE; + boolean alwaysMatches = match(shadow).alwaysTrue(); + Var var = isThis ? shadow.getThisVar() : shadow.getTargetVar(); + Var annVar = null; + TypeX annotationType = annotationTypePattern.annotationType; + if (annotationTypePattern instanceof BindingAnnotationTypePattern) { + BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern)annotationTypePattern; + annotationType = btp.annotationType; + annVar = isThis ? shadow.getThisAnnotationVar(annotationType) : + shadow.getTargetAnnotationVar(annotationType); + if (annVar == null) return Literal.TRUE; // should be exception when we implement properly + // Check if we have already bound something to this formal + if (state.get(btp.getFormalIndex())!=null) { + ISourceLocation pcdSloc = getSourceLocation(); + ISourceLocation shadowSloc = shadow.getSourceLocation(); + Message errorMessage = new Message( + "Cannot use @pointcut to match at this location and bind a formal to type '"+annVar.getType()+ + "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+ + ". The secondary source location points to the problematic binding.", + shadowSloc,true,new ISourceLocation[]{pcdSloc}); + shadow.getIWorld().getMessageHandler().handleMessage(errorMessage); + state.setErroneousVar(btp.getFormalIndex()); + } + state.set(btp.getFormalIndex(),annVar); + } + + if (alwaysMatches && (annVar == null)) { + return Literal.TRUE; + } else { + if (annVar != null) { + // TODO - need to bind it, next line is a placeholder + return Literal.FALSE; + } else { + ResolvedTypeX rType = annotationType.resolve(shadow.getIWorld()); + return Test.makeHasAnnotation(var,rType); + } + } } + + private boolean couldMatch(Shadow shadow) { + return isThis ? shadow.hasThis() : shadow.hasTarget(); + } + /* (non-Javadoc) * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream) */ public void write(DataOutputStream s) throws IOException { - // TODO Auto-generated method stub - + s.writeByte(Pointcut.ATTHIS_OR_TARGET); + s.writeBoolean(isThis); + annotationTypePattern.write(s); + writeLocation(s); } - + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + boolean isThis = s.readBoolean(); + AnnotationTypePattern type = AnnotationTypePattern.read(s, context); + ThisOrTargetAnnotationPointcut ret = new ThisOrTargetAnnotationPointcut(isThis,(ExactAnnotationTypePattern)type); + ret.readLocation(context, s); + return ret; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (!(obj instanceof ThisOrTargetAnnotationPointcut)) return false; + ThisOrTargetAnnotationPointcut other = (ThisOrTargetAnnotationPointcut) obj; + return ( other.annotationTypePattern.equals(this.annotationTypePattern) && + (other.isThis == this.isThis) ); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return 17 + 37*annotationTypePattern.hashCode() + (isThis ? 49 : 13); + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { StringBuffer buf = new StringBuffer(); buf.append(isThis ? "@this(" : "@target("); - buf.append(type.toString()); + buf.append(annotationTypePattern.toString()); buf.append(")"); return buf.toString(); } diff --git a/weaver/src/org/aspectj/weaver/weaver-messages.properties b/weaver/src/org/aspectj/weaver/weaver-messages.properties index cd86ab148..440faa772 100644 --- a/weaver/src/org/aspectj/weaver/weaver-messages.properties +++ b/weaver/src/org/aspectj/weaver/weaver-messages.properties @@ -121,4 +121,4 @@ itdmOnAnnotationNotAllowed=can''t make inter-type method declarations on annotat itdfOnAnnotationNotAllowed=can''t make inter-type field declarations on annotation types referenceToNonAnnotationType=Type referred to is not an annotation type: {0} - +bindingNonRuntimeRetentionAnnotation=Annotation type {0} does not have runtime retention -- 2.39.5