From: avasseur Date: Fri, 20 May 2005 12:27:59 +0000 (+0000) Subject: moved bcel things to bcel package in weaver, deow test + fix for @AJ X-Git-Tag: PRE_ANDY~298 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4f46be7c62e76950028e5e8a7214f209d6343bda;p=aspectj.git moved bcel things to bcel package in weaver, deow test + fix for @AJ --- diff --git a/docs/adk15ProgGuideDB/ataspectj.xml b/docs/adk15ProgGuideDB/ataspectj.xml index b3986ef90..febf50033 100644 --- a/docs/adk15ProgGuideDB/ataspectj.xml +++ b/docs/adk15ProgGuideDB/ataspectj.xml @@ -323,13 +323,13 @@ System.out.println("phew"); } - @AfterReturning(value="call(Foo+.new(..))",returning="f") + @AfterReturning(pointcut="call(Foo+.new(..))",returning="f") public void itsAFoo(Foo f) { System.out.println("It's a Foo: " + f); } ]]> - (Note the need for the "value=" prefix in front of the pointcut + (Note the use of the "pointcut=" prefix in front of the pointcut expression in the returning case). After throwing advice works in a similar fashion, using the diff --git a/tests/java5/ataspectj/ataspectj/DeowTest.java b/tests/java5/ataspectj/ataspectj/DeowTest.java new file mode 100644 index 000000000..fc8a27015 --- /dev/null +++ b/tests/java5/ataspectj/ataspectj/DeowTest.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2005 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: + * Alexandre Vasseur initial implementation + *******************************************************************************/ +package ataspectj; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.DeclareWarning; +import org.aspectj.lang.annotation.DeclareError; + +/** + * @author Alexandre Vasseur + */ +public class DeowTest { + + public void hello() {} + + public void hi() {} + + public void target() { + hello(); + hi(); + } + + @Aspect + public static class DeowAspect { + + @DeclareWarning("call(* hello()) && within(ataspectj.DeowTest)") + final static String onHello = "call hello"; + + @DeclareError("call(* hi()) && within(ataspectj.DeowTest)") + final static String onHi = "call hi"; + } +} diff --git a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/AtAjSyntaxTests.java b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/AtAjSyntaxTests.java index 264c46930..6c936ef4f 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/AtAjSyntaxTests.java +++ b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/AtAjSyntaxTests.java @@ -87,4 +87,8 @@ public class AtAjSyntaxTests extends XMLBasedAjcTestCase { public void testAroundInlineMunger2() { runTest("AroundInlineMunger2"); } + + public void testDeow() { + runTest("Deow"); + } } \ No newline at end of file diff --git a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml index 055567d30..2a4024617 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml +++ b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml @@ -100,4 +100,11 @@ + + + + + + + \ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/AjcMemberMaker.java b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java index 83bab19e0..a80e7e3a7 100644 --- a/weaver/src/org/aspectj/weaver/AjcMemberMaker.java +++ b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java @@ -13,6 +13,9 @@ package org.aspectj.weaver; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; + import java.lang.reflect.Modifier; //import org.aspectj.weaver.ResolvedTypeX.Name; @@ -692,4 +695,22 @@ public class AjcMemberMaker { "", "()V"); } + + //-- common types we use. Note: Java 5 dependand types are refered to as String + public final static TypeX ASPECT_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Aspect"); + public final static TypeX BEFORE_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Before"); + public final static TypeX AROUND_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Around"); + public final static TypeX AFTERRETURNING_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.AfterReturning"); + public final static TypeX AFTERTHROWING_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.AfterThrowing"); + public final static TypeX AFTER_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.After"); + public final static TypeX POINTCUT_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.Pointcut"); + public final static TypeX DECLAREERROR_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.DeclareError"); + public final static TypeX DECLAREWARNING_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.DeclareWarning"); + public final static TypeX DECLAREPRECEDENCE_ANNOTATION = TypeX.forName("org.aspectj.lang.annotation.DeclarePrecedence"); + + public final static TypeX TYPEX_JOINPOINT = TypeX.forName(JoinPoint.class.getName().replace('/','.')); + public final static TypeX TYPEX_PROCEEDINGJOINPOINT = TypeX.forName(ProceedingJoinPoint.class.getName().replace('/','.')); + public final static TypeX TYPEX_STATICJOINPOINT = TypeX.forName(JoinPoint.StaticPart.class.getName().replace('/','.')); + public final static TypeX TYPEX_ENCLOSINGSTATICJOINPOINT = TypeX.forName(JoinPoint.EnclosingStaticPart.class.getName().replace('/','.')); + } diff --git a/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java b/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java deleted file mode 100644 index 15896cbc6..000000000 --- a/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java +++ /dev/null @@ -1,1261 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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: - * initial implementation Alexandre Vasseur - *******************************************************************************/ -package org.aspectj.weaver.ataspectj; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; - -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.Field; -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.Method; -import org.aspectj.apache.bcel.classfile.annotation.Annotation; -import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; -import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations; -import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.IMessage; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AdviceKind; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedPointcutDefinition; -import org.aspectj.weaver.ResolvedTypeX; -import org.aspectj.weaver.TypeX; -import org.aspectj.weaver.patterns.DeclarePrecedence; -import org.aspectj.weaver.patterns.FormalBinding; -import org.aspectj.weaver.patterns.IScope; -import org.aspectj.weaver.patterns.PatternParser; -import org.aspectj.weaver.patterns.PerCflow; -import org.aspectj.weaver.patterns.PerClause; -import org.aspectj.weaver.patterns.PerObject; -import org.aspectj.weaver.patterns.PerSingleton; -import org.aspectj.weaver.patterns.PerTypeWithin; -import org.aspectj.weaver.patterns.Pointcut; -import org.aspectj.weaver.patterns.SimpleScope; -import org.aspectj.weaver.patterns.ParserException; -import org.aspectj.weaver.patterns.Declare; -import org.aspectj.weaver.patterns.DeclareErrorOrWarning; - -/** - * Annotation defined aspect reader. - *

- * It reads the Java 5 annotations and turns them into AjAttributes - * - * @author Alexandre Vasseur - */ -public class Aj5Attributes { - - private final static List EMPTY_LIST = new ArrayList(); - private final static String[] EMPTY_STRINGS = new String[0]; - - public final static TypeX TYPEX_JOINPOINT = TypeX.forName(JoinPoint.class.getName().replace('/','.')); - public final static TypeX TYPEX_PROCEEDINGJOINPOINT = TypeX.forName(ProceedingJoinPoint.class.getName().replace('/','.')); - public final static TypeX TYPEX_STATICJOINPOINT = TypeX.forName(JoinPoint.StaticPart.class.getName().replace('/','.')); - public final static TypeX TYPEX_ENCLOSINGSTATICJOINPOINT = TypeX.forName(JoinPoint.EnclosingStaticPart.class.getName().replace('/','.')); - - /** - * A struct that allows to add extra arguments without always breaking the API - * - * @author Alexandre Vasseur - */ - private static class AjAttributeStruct { - - /** - * The list of AjAttribute.XXX that we are populating from the @AJ read - */ - List ajAttributes = new ArrayList(); - - /** - * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations) - */ - final ResolvedTypeX enclosingType; - - final ISourceContext context; - final IMessageHandler handler; - - public AjAttributeStruct(ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) { - enclosingType = type; - context = sourceContext; - handler = messageHandler; - } - } - - /** - * A struct when we read @AJ on method - * - * @author Alexandre Vasseur - */ - private static class AjAttributeMethodStruct extends AjAttributeStruct { - - /** - * Argument names as they appear in the SOURCE code, ordered, and lazyly populated - * Used to do formal binding - */ - private String[] m_argumentNamesLazy = null; - - final Method method; - - public AjAttributeMethodStruct(Method method, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) { - super(type, sourceContext, messageHandler); - this.method = method; - } - - public String[] getArgumentNames() { - if (m_argumentNamesLazy == null) { - m_argumentNamesLazy = getMethodArgumentNamesAsInSource(method); - } - return m_argumentNamesLazy; - } - } - - /** - * A struct when we read @AJ on field - * - * @author Alexandre Vasseur - */ - private static class AjAttributeFieldStruct extends AjAttributeStruct { - - final Field field; - - public AjAttributeFieldStruct(Field field, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) { - super(type, sourceContext, messageHandler); - this.field = field; - } - } - - /** - * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones. - * - * @param attribute - * @return - */ - public static boolean acceptAttribute(Attribute attribute) { - return (attribute instanceof RuntimeVisibleAnnotations); - } - - /** - * Extract class level annotations and turn them into AjAttributes. - * - * @param javaClass - * @param type - * @param context - * @param msgHandler - * @return list of AjAttributes - */ - public static List readAj5ClassAttributes(JavaClass javaClass, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler, boolean isCodeStyleAspect) { - AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler); - Attribute[] attributes = javaClass.getAttributes(); - boolean hasAtAspectAnnotation = false; - boolean hasAtPrecedenceAnnotation = false; - - for (int i = 0; i < attributes.length; i++) { - Attribute attribute = attributes[i]; - if (acceptAttribute(attribute)) { - RuntimeAnnotations rvs = (RuntimeAnnotations) attribute; - // we don't need to look for several attribute occurence since it cannot happen as per JSR175 - if (!isCodeStyleAspect) { - hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct); - } - //TODO: below means mix style for @DeclarePrecedence - are we sure we want that ? - hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct); - // there can only be one RuntimeVisible bytecode attribute - break; - } - } - - // basic semantic check - //FIXME AV TBD could be skipped and silently ignore - TBD with Andy - if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) { - msgHandler.handleMessage( - new Message( - "Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'", - IMessage.WARNING, - null, - type.getSourceLocation() - ) - ); - // bypass what we have read - return EMPTY_LIST; - } - //FIXME turn on when ajcMightHaveAspect fixed -// if (hasAtAspectAnnotation && type.isInterface()) { -// msgHandler.handleMessage( -// new Message( -// "Found @Aspect on an interface type '" + type.getName() + "'", -// IMessage.WARNING, -// null, -// type.getSourceLocation() -// ) -// ); -// // bypass what we have read -// return EMPTY_LIST; -// } - - // the following block will not detect @Pointcut in non @Aspect types for optimization purpose - // FIXME AV TBD with Andy - if (!hasAtAspectAnnotation) { - return EMPTY_LIST; - } - - // code style pointcuts are class attributes - // we need to gather the @AJ pointcut right now and not at method level annotation extraction time - // in order to be able to resolve the pointcut references later on - //FIXME alex loop over class super class - //FIXME alex can that be too slow ? - for (int i = 0; i < javaClass.getMethods().length; i++) { - Method method = javaClass.getMethods()[i]; - if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc... - //FIXME alex optimize, this method struct will gets recreated for advice extraction - AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, type, context, msgHandler); - Attribute[] mattributes = method.getAttributes(); - - for (int j = 0; j < mattributes.length; j++) { - Attribute mattribute = mattributes[j]; - if (acceptAttribute(mattribute)) { - RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute; - handlePointcutAnnotation(mrvs, mstruct); - // there can only be one RuntimeVisible bytecode attribute - break; - } - } - struct.ajAttributes.addAll(mstruct.ajAttributes); - } - - - // code style declare error / warning are class attributes - for (int i = 0; i < javaClass.getFields().length; i++) { - Field field = javaClass.getFields()[i]; - if (field.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc... - //FIXME alex optimize, this method struct will gets recreated for advice extraction - AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, type, context, msgHandler); - Attribute[] fattributes = field.getAttributes(); - - for (int j = 0; j < fattributes.length; j++) { - Attribute fattribute = fattributes[j]; - if (acceptAttribute(fattribute)) { - RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute; - if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct)) { - // semantic check - must be in an @Aspect [remove if previous block bypassed in advance] - if (!type.isAnnotationStyleAspect()) { - msgHandler.handleMessage( - new Message( - "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'", - IMessage.WARNING, - null, - type.getSourceLocation() - ) - ); - ;// go ahead - } - } - // there can only be one RuntimeVisible bytecode attribute - break; - } - } - struct.ajAttributes.addAll(fstruct.ajAttributes); - } - return struct.ajAttributes; - } - - /** - * Extract method level annotations and turn them into AjAttributes. - * - * @param method - * @param type - * @param context - * @param msgHandler - * @return list of AjAttributes - */ - public static List readAj5MethodAttributes(Method method, ResolvedTypeX type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context,IMessageHandler msgHandler) { - if (method.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc... - - AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, type, context, msgHandler); - Attribute[] attributes = method.getAttributes(); - - // we remember if we found one @AJ annotation for minimal semantic error reporting - // the real reporting beeing done thru AJDT and the compiler mapping @AJ to AjAtttribute - // or thru APT - // FIXME AV we could actually skip the whole thing if type is not itself an @Aspect - // but then we would not see any warning. TBD with Andy - boolean hasAtAspectJAnnotation = false; - boolean hasAtAspectJAnnotationMustReturnVoid = false; - for (int i = 0; i < attributes.length; i++) { - Attribute attribute = attributes[i]; - if (acceptAttribute(attribute)) { - RuntimeAnnotations rvs = (RuntimeAnnotations) attribute; - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(rvs, struct, preResolvedPointcut); - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(rvs, struct, preResolvedPointcut); - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut); - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut); - hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(rvs, struct, preResolvedPointcut); - // there can only be one RuntimeVisible bytecode attribute - break; - } - } - hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid; - - // semantic check - must be in an @Aspect [remove if previous block bypassed in advance] - if (hasAtAspectJAnnotation && !type.isAnnotationStyleAspect()) { - msgHandler.handleMessage( - new Message( - "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'", - IMessage.WARNING, - null, - type.getSourceLocation() - ) - ); - ;// go ahead - } - // semantic check - advice must be public - if (hasAtAspectJAnnotation && !struct.method.isPublic()) { - msgHandler.handleMessage( - new Message( - "Found @AspectJ annotation on a non public advice '" + methodToString(struct.method) + "'", - IMessage.ERROR, - null, - type.getSourceLocation() - ) - ); - ;// go ahead - } - // semantic check for non around advice must return void - if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) { - msgHandler.handleMessage( - new Message( - "Found @AspectJ annotation on a non around advice not returning void '" + methodToString(struct.method) + "'", - IMessage.ERROR, - null, - type.getSourceLocation() - ) - ); - ;// go ahead - } - - - return struct.ajAttributes; - } - - /** - * Extract field level annotations and turn them into AjAttributes. - * - * @param field - * @param type - * @param context - * @param msgHandler - * @return list of AjAttributes, always empty for now - */ - public static List readAj5FieldAttributes(Field field, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler) { - return Collections.EMPTY_LIST; - } - - /** - * Read @Aspect - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAspectAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) { - Annotation aspect = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Aspect"); - if (aspect != null) { - ElementNameValuePair aspectPerClause = getAnnotationElement(aspect, "value"); - if (aspectPerClause == null) { - // defaults to singleton - PerClause clause = new PerSingleton(); - clause.setLocation(struct.context, -1, -1); - struct.ajAttributes.add(new AjAttribute.Aspect(clause)); - return true; - } else { - String perX = aspectPerClause.getValue().stringifyValue(); - final PerClause clause; - if (perX == null || perX.length()<=0) { - clause = new PerSingleton(); - } else { - clause = parsePerClausePointcut(perX, struct); - } - clause.setLocation(struct.context, -1, -1); - struct.ajAttributes.add(new AjAttribute.Aspect(clause)); - return true; - } - } - return false; - } - - /** - * Read a perClause - * - * @param perClause like "pertarget(.....)" - * @param struct for which we are parsing the per clause - * @return a PerClause instance - */ - private static PerClause parsePerClausePointcut(String perClause, AjAttributeStruct struct) { - final String pointcut; - if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) { - pointcut = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClause); - return new PerCflow(Pointcut.fromString(pointcut), false); - } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) { - pointcut = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClause); - return new PerCflow(Pointcut.fromString(pointcut), true); - } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) { - pointcut = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClause); - return new PerObject(Pointcut.fromString(pointcut), false); - } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) { - pointcut = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClause); - return new PerObject(Pointcut.fromString(pointcut), true); - } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) { - pointcut = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClause); - return new PerTypeWithin(new PatternParser(pointcut).parseTypePattern()); - } else if (perClause.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) { - return new PerSingleton(); - } - // could not parse the @AJ perclause - struct.handler.handleMessage( - new Message( - "cannot read per clause from @Aspect: " + perClause, - struct.enclosingType.getSourceLocation(), - true - ) - ); - throw new RuntimeException("cannot read perclause " + perClause); - } - - /** - * Read @DeclarePrecedence - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handlePrecedenceAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) { - Annotation aspect = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.DeclarePrecedence"); - if (aspect != null) { - ElementNameValuePair precedence = getAnnotationElement(aspect, "value"); - if (precedence != null) { - String precedencePattern = precedence.getValue().stringifyValue(); - PatternParser parser = new PatternParser(precedencePattern); - DeclarePrecedence ajPrecedence = parser.parseDominates(); - struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence)); - return true; - } - } - return false; - } - - /** - * Read @Before - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { - Annotation before = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Before"); - if (before != null) { - ElementNameValuePair beforeAdvice = getAnnotationElement(before, "value"); - if (beforeAdvice != null) { - // this/target/args binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = extractBindings(struct); - } catch (UnreadableDebugInfo unreadableDebugInfo) { - return false; - } - IScope binding = new BindingScope( - struct.enclosingType, - bindings - ); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = Pointcut.fromString(beforeAdvice.getValue().stringifyValue()).resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - struct.ajAttributes.add(new AjAttribute.AdviceAttribute( - AdviceKind.Before, - pc, - extraArgument, - -1, - -1, - struct.context - ) - ); - return true; - } - } - return false; - } - - /** - * Read @After - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { - Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.After"); - if (after != null) { - ElementNameValuePair afterAdvice = getAnnotationElement(after, "value"); - if (afterAdvice != null) { - // this/target/args binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = extractBindings(struct); - } catch (UnreadableDebugInfo unreadableDebugInfo) { - return false; - } - IScope binding = new BindingScope( - struct.enclosingType, - bindings - ); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = Pointcut.fromString(afterAdvice.getValue().stringifyValue()).resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - struct.ajAttributes.add(new AjAttribute.AdviceAttribute( - AdviceKind.After, - pc, - extraArgument, - -1, - -1, - struct.context - ) - ); - return true; - } - } - return false; - } - - /** - * Read @AfterReturning - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { - Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.AfterReturning"); - if (after != null) { - ElementNameValuePair annValue = getAnnotationElement(after, "value"); - ElementNameValuePair annPointcut = getAnnotationElement(after, "pointcut"); - ElementNameValuePair annReturned = getAnnotationElement(after, "returning"); - - // extract the pointcut and returned type/binding - do some checks - String pointcut = null; - String returned = null; - if ((annValue!=null && annPointcut!=null) || (annValue==null && annPointcut==null)) { - struct.handler.handleMessage( - new Message( - "@AfterReturning: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method), - struct.enclosingType.getSourceLocation(), - true - ) - ); - return false; - } - if (annValue != null) { - pointcut = annValue.getValue().stringifyValue(); - } else { - pointcut = annPointcut.getValue().stringifyValue(); - } - if (isNullOrEmpty(pointcut)) { - struct.handler.handleMessage( - new Message( - "@AfterReturning: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method), - struct.enclosingType.getSourceLocation(), - true - ) - ); - return false; - } - if (annReturned!=null) { - returned = annReturned.getValue().stringifyValue(); - if (isNullOrEmpty(returned)) - returned = null; - } - - // this/target/args binding - // exclude the return binding from the pointcut binding since it is an extraArg binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = (returned==null?extractBindings(struct):extractBindings(struct, returned)); - } catch (UnreadableDebugInfo unreadableDebugInfo) { - return false; - } - IScope binding = new BindingScope( - struct.enclosingType, - bindings - ); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - // return binding - if (returned != null) { - extraArgument |= Advice.ExtraArgument; - } - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = Pointcut.fromString(pointcut).resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - pc.setLocation(struct.enclosingType.getSourceContext(), 0, 0);//TODO method location ? - - struct.ajAttributes.add(new AjAttribute.AdviceAttribute( - AdviceKind.AfterReturning, - pc, - extraArgument, - -1, - -1, - struct.context - ) - ); - return true; - } - return false; - } - - /** - * Read @AfterThrowing - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { - Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.AfterThrowing"); - if (after != null) { - ElementNameValuePair annValue = getAnnotationElement(after, "value"); - ElementNameValuePair annPointcut = getAnnotationElement(after, "pointcut"); - ElementNameValuePair annThrowned = getAnnotationElement(after, "throwing"); - - // extract the pointcut and throwned type/binding - do some checks - String pointcut = null; - String throwned = null; - if ((annValue!=null && annPointcut!=null) || (annValue==null && annPointcut==null)) { - struct.handler.handleMessage( - new Message( - "@AfterThrowing: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method), - struct.enclosingType.getSourceLocation(), - true - ) - ); - return false; - } - if (annValue != null) { - pointcut = annValue.getValue().stringifyValue(); - } else { - pointcut = annPointcut.getValue().stringifyValue(); - } - if (isNullOrEmpty(pointcut)) { - struct.handler.handleMessage( - new Message( - "@AfterThrowing: either 'value' or 'poincut' must be provided, not both: " + methodToString(struct.method), - struct.enclosingType.getSourceLocation(), - true - ) - ); - return false; - } - if (annThrowned!=null) { - throwned = annThrowned.getValue().stringifyValue(); - if (isNullOrEmpty(throwned)) - throwned = null; - } - - // this/target/args binding - // exclude the throwned binding from the pointcut binding since it is an extraArg binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = (throwned==null?extractBindings(struct):extractBindings(struct, throwned)); - } catch (UnreadableDebugInfo unreadableDebugInfo) { - return false; - } - IScope binding = new BindingScope( - struct.enclosingType, - bindings - ); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - // return binding - if (throwned != null) { - extraArgument |= Advice.ExtraArgument; - } - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = Pointcut.fromString(pointcut).resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - struct.ajAttributes.add(new AjAttribute.AdviceAttribute( - AdviceKind.AfterThrowing, - pc, - extraArgument, - -1, - -1, - struct.context - ) - ); - return true; - } - return false; - } - - /** - * Read @Around - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { - Annotation around = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Around"); - if (around != null) { - ElementNameValuePair aroundAdvice = getAnnotationElement(around, "value"); - if (aroundAdvice != null) { - // this/target/args binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = extractBindings(struct); - } catch (UnreadableDebugInfo unreadableDebugInfo) { - return false; - } - IScope binding = new BindingScope( - struct.enclosingType, - bindings - ); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = Pointcut.fromString(aroundAdvice.getValue().stringifyValue()).resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - struct.ajAttributes.add(new AjAttribute.AdviceAttribute( - AdviceKind.Around, - pc, - extraArgument, - -1, - -1, - struct.context - ) - ); - return true; - } - } - return false; - } - - /** - * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references - * - * @param runtimeAnnotations - * @param struct - */ - private static void handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { - Annotation pointcut = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Pointcut"); - if (pointcut != null) { - ElementNameValuePair pointcutExpr = getAnnotationElement(pointcut, "value"); - if (pointcutExpr != null) { - - // semantic check: the method must return void - if (!Type.VOID.equals(struct.method.getReturnType())) { - struct.handler.handleMessage( - new Message( - "Found @Pointcut on a method not returning void '" + methodToString(struct.method) + "'", - IMessage.WARNING, - null, - struct.enclosingType.getSourceLocation()//TODO method loc instead how ? - ) - ); - //TODO AV : Andy - should we stop ? - return; - } - // semantic check: the method must not throw anything - if (struct.method.getExceptionTable() != null) { - struct.handler.handleMessage( - new Message( - "Found @Pointcut on a method throwing exception '" + methodToString(struct.method) + "'", - IMessage.WARNING, - null, - struct.enclosingType.getSourceLocation()//TODO method loc instead how ? - ) - ); - //TODO AV : Andy - should we stop ? - return; - } - - // this/target/args binding - final IScope binding; - try { - binding = new BindingScope( - struct.enclosingType, - extractBindings(struct) - ); - } catch(UnreadableDebugInfo e) { - return; - } - - TypeX[] argumentTypes = new TypeX[struct.method.getArgumentTypes().length]; - for (int i = 0; i < argumentTypes.length; i++) { - argumentTypes[i] = TypeX.forSignature(struct.method.getArgumentTypes()[i].getSignature()); - } - - // use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily - // since for it to be resolved, we will need other pointcuts to be registered as well - try { - struct.ajAttributes.add(new AjAttribute.PointcutDeclarationAttribute( - new LazyResolvedPointcutDefinition( - struct.enclosingType, - struct.method.getModifiers(), - struct.method.getName(), - argumentTypes, - Pointcut.fromString(pointcutExpr.getValue().stringifyValue()), - binding - ) - )); - } catch (ParserException e) { - struct.handler.handleMessage( - new Message( - "Cannot parse @Pointcut '" + pointcutExpr.getValue().stringifyValue() + "'", - IMessage.ERROR, - e, - struct.enclosingType.getSourceLocation()//TODO method loc instead how ? - ) - ); - return; - } - } - } - } - - /** - * Read @DeclareError, @DeclareWarning - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleDeclareErrorOrWarningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) { - Annotation error = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.DeclareError"); - boolean hasError = false; - if (error != null) { - ElementNameValuePair declareError = getAnnotationElement(error, "value"); - if (declareError != null) { - if (!"Ljava/lang/String;".equals(struct.field.getSignature()) || struct.field.getConstantValue()==null) { - struct.handler.handleMessage( - new Message( - "@DeclareError used on a non String constant field " + fieldToString(struct.field), - struct.enclosingType.getSourceLocation(), - true - )); - return false; - } - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - IScope binding = new BindingScope( - struct.enclosingType, - bindings - ); - Pointcut pc = Pointcut.fromString(declareError.getValue().stringifyValue()).resolve(binding); - struct.ajAttributes.add(new AjAttribute.DeclareAttribute( - new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString()) - )); - return hasError = true; - } - } - Annotation warning = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.DeclareWarning"); - boolean hasWarning = false; - if (warning != null) { - ElementNameValuePair declareWarning = getAnnotationElement(warning, "value"); - if (declareWarning != null) { - if (!"Ljava/lang/String;".equals(struct.field.getSignature()) || struct.field.getConstantValue()==null) { - struct.handler.handleMessage( - new Message( - "@DeclareWarning used on a non String constant field " + fieldToString(struct.field), - struct.enclosingType.getSourceLocation(), - true - )); - return false; - } - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - IScope binding = new BindingScope( - struct.enclosingType, - bindings - ); - Pointcut pc = Pointcut.fromString(declareWarning.getValue().stringifyValue()).resolve(binding); - struct.ajAttributes.add(new AjAttribute.DeclareAttribute( - new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString()) - )); - return hasWarning = true; - } - } - return hasError || hasWarning; - } - - /** - * Returns a readable representation of a method. - * Method.toString() is not suitable. - * - * @param method - * @return - */ - private static String methodToString(Method method) { - StringBuffer sb = new StringBuffer(); - sb.append(method.getName()); - sb.append(method.getSignature()); - return sb.toString(); - } - - /** - * Returns a readable representation of a field. - * Field.toString() is not suitable. - * - * @param field - * @return - */ - private static String fieldToString(Field field) { - StringBuffer sb = new StringBuffer(); - sb.append(field.getName()).append(' '); - sb.append(field.getSignature()); - return sb.toString(); - } - - /** - * Build the bindings for a given method (pointcut / advice) - * - * @param struct - * @return null if no debug info is available - */ - private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct) - throws UnreadableDebugInfo { - Method method = struct.method; - String[] argumentNames = struct.getArgumentNames(); - - // assert debug info was here - if (argumentNames.length != method.getArgumentTypes().length) { - struct.handler.handleMessage( - new Message( - "Cannot read debug info for @Aspect '" + struct.enclosingType.getName() + "'" - + " (please compile with 'javac -g' or '' in Ant)", - IMessage.FAIL, - null, - struct.enclosingType.getSourceLocation() - ) - ); - throw new UnreadableDebugInfo(); - } - - List bindings = new ArrayList(); - for (int i = 0; i < argumentNames.length; i++) { - String argumentName = argumentNames[i]; - TypeX argumentType = TypeX.forSignature(method.getArgumentTypes()[i].getSignature()); - - // do not bind JoinPoint / StaticJoinPoint / EnclosingStaticJoinPoint - // TODO solve me : this means that the JP/SJP/ESJP cannot appear as binding - // f.e. when applying advice on advice etc - if ((TYPEX_JOINPOINT.equals(argumentType) - || TYPEX_PROCEEDINGJOINPOINT.equals(argumentType) - || TYPEX_STATICJOINPOINT.equals(argumentType) - || TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType) - || AjcMemberMaker.AROUND_CLOSURE_TYPE.equals(argumentType))) { - //continue;// skip - bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i)); - } else { - bindings.add(new FormalBinding(argumentType, argumentName, i)); - } - } - - return (FormalBinding[]) bindings.toArray(new FormalBinding[]{}); - } - - //FIXME alex deal with exclude index - private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal) - throws UnreadableDebugInfo { - FormalBinding[] bindings = extractBindings(struct); - int excludeIndex = -1; - for (int i = 0; i < bindings.length; i++) { - FormalBinding binding = bindings[i]; - if (binding.getName().equals(excludeFormal)) { - excludeIndex = i; - bindings[i] = new FormalBinding.ImplicitFormalBinding(binding.getType(), binding.getName(), binding.getIndex()); - break; - } - } - return bindings; -// -// if (excludeIndex >= 0) { -// FormalBinding[] bindingsFiltered = new FormalBinding[bindings.length-1]; -// int k = 0; -// for (int i = 0; i < bindings.length; i++) { -// if (i == excludeIndex) { -// ; -// } else { -// bindingsFiltered[k] = new FormalBinding(bindings[i].getType(), bindings[i].getName(), k); -// k++; -// } -// } -// return bindingsFiltered; -// } else { -// return bindings; -// } - } - - - /** - * Compute the flag for the xxxJoinPoint extra argument - * - * @param method - * @return - */ - private static int extractExtraArgument(Method method) { - int extraArgument = 0; - Type[] methodArgs = method.getArgumentTypes(); - for (int i = 0; i < methodArgs.length; i++) { - String methodArg = methodArgs[i].getSignature(); - if (TYPEX_JOINPOINT.getSignature().equals(methodArg)) { - extraArgument |= Advice.ThisJoinPoint; - } else if (TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(methodArg)) { - extraArgument |= Advice.ThisJoinPoint; - } else if (TYPEX_STATICJOINPOINT.getSignature().equals(methodArg)) { - extraArgument |= Advice.ThisJoinPointStaticPart; - } else if (TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(methodArg)) { - extraArgument |= Advice.ThisEnclosingJoinPointStaticPart; - } - } - return extraArgument; - } - - /** - * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation - * - * @param rvs - * @param annotationType - * @return - */ - private static Annotation getAnnotation(RuntimeAnnotations rvs, String annotationType) { - for (Iterator iterator = rvs.getAnnotations().iterator(); iterator.hasNext();) { - Annotation rv = (Annotation) iterator.next(); - if (annotationType.equals(rv.getTypeName())) { - return rv; - } - } - return null; - } - - /** - * Returns the value of a given element of an annotation or null if not found - * Caution: Does not handles default value. - * - * @param annotation - * @param elementName - * @return - */ - private static ElementNameValuePair getAnnotationElement(Annotation annotation, String elementName) { - for (Iterator iterator1 = annotation.getValues().iterator(); iterator1.hasNext();) { - ElementNameValuePair element = (ElementNameValuePair) iterator1.next(); - if (elementName.equals(element.getNameString())) { - return element; - } - } - return null; - } - - /** - * Extract the method argument names as in source from debug info - * returns an empty array upon inconsistency - * - * @param method - * @return - */ - private static String[] getMethodArgumentNamesAsInSource(Method method) { - if (method.getArgumentTypes().length == 0) { - return EMPTY_STRINGS; - } - - final int startAtStackIndex = method.isStatic()?0:1; - final List arguments = new ArrayList(); - LocalVariableTable lt = (LocalVariableTable) method.getLocalVariableTable(); - if (lt != null) { - for (int j = 0; j < lt.getLocalVariableTable().length; j++) { - LocalVariable localVariable = lt.getLocalVariableTable()[j]; - if (localVariable.getStartPC() == 0) { - if (localVariable.getIndex() >= startAtStackIndex) { - arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex())); - } - } - } - } - - if (arguments.size() != method.getArgumentTypes().length) { - //throw new RuntimeException("cannot access debug info on " + method); - return EMPTY_STRINGS; - } - - // sort by index - Collections.sort(arguments, new Comparator() { - public int compare(Object o, Object o1) { - MethodArgument mo = (MethodArgument)o; - MethodArgument mo1 = (MethodArgument) o1; - if (mo.indexOnStack == mo1.indexOnStack) { - return 0; - } else if (mo.indexOnStack > mo1.indexOnStack) { - return 1; - } else { - return -1; - } - } - }); - String[] argumentNames = new String[arguments.size()]; - int i = 0; - for (Iterator iterator = arguments.iterator(); iterator.hasNext(); i++) { - MethodArgument methodArgument = (MethodArgument) iterator.next(); - argumentNames[i] = methodArgument.name; - } - return argumentNames; - } - - /** - * A method argument, used for sorting by indexOnStack (ie order in signature) - * - * @author Alexandre Vasseur - */ - private static class MethodArgument { - String name; - int indexOnStack; - public MethodArgument(String name, int indexOnStack) { - this.name = name; - this.indexOnStack = indexOnStack; - } - } - - /** - * BindingScope that knows the enclosingType, which is needed for pointcut reference resolution - * - * @author Alexandre Vasseur - */ - public static class BindingScope extends SimpleScope { - private ResolvedTypeX m_enclosingType; - - public BindingScope(ResolvedTypeX type, FormalBinding[] bindings) { - super(type.getWorld(), bindings); - m_enclosingType = type; - } - - public ResolvedTypeX getEnclosingType() { - return m_enclosingType; - } - } - - /** - * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all - * pointcut referenced before pointcut resolution happens - * - * @author Alexandre Vasseur - */ - public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition { - private Pointcut m_pointcutUnresolved; - private IScope m_binding; - - private Pointcut m_lazyPointcut = null; - - public LazyResolvedPointcutDefinition(ResolvedTypeX declaringType, int modifiers, String name, TypeX[] parameterTypes, - Pointcut pointcut, IScope binding) { - super(declaringType, modifiers, name, parameterTypes, null); - m_pointcutUnresolved = pointcut; - m_binding = binding; - m_pointcutUnresolved.setLocation(declaringType.getSourceContext(), 0, 0); - } - - public Pointcut getPointcut() { - if (m_lazyPointcut == null) { - m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding); - m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved); - } - return m_lazyPointcut; - } - } - - /** - * Helper to test empty strings - * @param s - * @return - */ - private static boolean isNullOrEmpty(String s) { - return (s==null || s.length()<=0); - } - - /** - * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind - * xxxJoinPoint for @AJ advices - * - * @param pointcut - * @param bindings - */ - private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) { - // register ImplicitBindings as to be ignored since unbound - // TODO is it likely to fail in a bad way if f.e. this(jp) etc ? - List ignores = new ArrayList(); - for (int i = 0; i < bindings.length; i++) { - FormalBinding formalBinding = bindings[i]; - if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) { - ignores.add(formalBinding.getName()); - } - } - pointcut.m_ignoreUnboundBindingForNames = (String[])ignores.toArray(new String[ignores.size()]); - } - - /** - * A check exception when we cannot read debug info (needed for formal binding) - */ - private static class UnreadableDebugInfo extends Exception { - } -} diff --git a/weaver/src/org/aspectj/weaver/ataspectj/Ajc5MemberMaker.java b/weaver/src/org/aspectj/weaver/ataspectj/Ajc5MemberMaker.java deleted file mode 100644 index e6f68d7ff..000000000 --- a/weaver/src/org/aspectj/weaver/ataspectj/Ajc5MemberMaker.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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: - * initial implementation Alexandre Vasseur - *******************************************************************************/ -package org.aspectj.weaver.ataspectj; - -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.TypeX; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.ResolvedTypeX; - -import java.lang.reflect.Modifier; - -/** - * Addition to AjcMemberMaker for @Aj aspect - * Should end up there - * - * @author Alexandre Vasseur - */ -public class Ajc5MemberMaker { - - public final static TypeX ASPECT = TypeX.forName("org.aspectj.lang.annotation.Aspect"); - - /** - * Returns true if the given aspect is an @AJ aspect - * - * @param aspectType - * @return - */ - public static boolean isAnnotationStyleAspect(ResolvedTypeX aspectType) { - if (aspectType != null) { - if (aspectType.isAspect()) { - return aspectType.isAnnotationStyleAspect(); - } - } - return false; - } - - //temp proto code for aspectOf without pre-processing - public static ResolvedMember perSingletonAspectOfMethod(TypeX declaringType) { - return new ResolvedMember( - Member.METHOD, - TypeX.forName("alex.lang.Aspects"), - Modifier.PUBLIC | Modifier.STATIC, - "aspectOf$singleton", - "(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;" - ); - - - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java b/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java new file mode 100644 index 000000000..154ec2748 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java @@ -0,0 +1,1325 @@ +/******************************************************************************* + * Copyright (c) 2005 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: + * initial implementation Alexandre Vasseur + *******************************************************************************/ +package org.aspectj.weaver.bcel; + +import org.aspectj.apache.bcel.classfile.Attribute; +import org.aspectj.apache.bcel.classfile.Field; +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.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; +import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; +import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations; +import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations; +import org.aspectj.apache.bcel.generic.Type; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.bridge.Message; +import org.aspectj.weaver.Advice; +import org.aspectj.weaver.AdviceKind; +import org.aspectj.weaver.AjAttribute; +import org.aspectj.weaver.AjcMemberMaker; +import org.aspectj.weaver.ISourceContext; +import org.aspectj.weaver.NameMangler; +import org.aspectj.weaver.ResolvedPointcutDefinition; +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.TypeX; +import org.aspectj.weaver.patterns.DeclareErrorOrWarning; +import org.aspectj.weaver.patterns.DeclarePrecedence; +import org.aspectj.weaver.patterns.FormalBinding; +import org.aspectj.weaver.patterns.IScope; +import org.aspectj.weaver.patterns.ParserException; +import org.aspectj.weaver.patterns.PatternParser; +import org.aspectj.weaver.patterns.PerCflow; +import org.aspectj.weaver.patterns.PerClause; +import org.aspectj.weaver.patterns.PerObject; +import org.aspectj.weaver.patterns.PerSingleton; +import org.aspectj.weaver.patterns.PerTypeWithin; +import org.aspectj.weaver.patterns.Pointcut; +import org.aspectj.weaver.patterns.SimpleScope; +import org.aspectj.weaver.patterns.TypePattern; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * Annotation defined aspect reader. + *

+ * It reads the Java 5 annotations and turns them into AjAttributes + * + * @author Alexandre Vasseur + */ +public class AtAjAttributes { + + private final static List EMPTY_LIST = new ArrayList(); + private final static String[] EMPTY_STRINGS = new String[0]; + private final static String VALUE = "value"; + private final static String POINTCUT = "pointcut"; + private final static String THROWING = "throwing"; + private final static String RETURNING = "returning"; + private final static String STRING_DESC = "Ljava/lang/String;"; + + /** + * A struct that allows to add extra arguments without always breaking the API + * + * @author Alexandre Vasseur + */ + private static class AjAttributeStruct { + + /** + * The list of AjAttribute.XXX that we are populating from the @AJ read + */ + List ajAttributes = new ArrayList(); + + /** + * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations) + */ + final ResolvedTypeX enclosingType; + + final ISourceContext context; + final IMessageHandler handler; + + public AjAttributeStruct(ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) { + enclosingType = type; + context = sourceContext; + handler = messageHandler; + } + } + + /** + * A struct when we read @AJ on method + * + * @author Alexandre Vasseur + */ + private static class AjAttributeMethodStruct extends AjAttributeStruct { + + /** + * Argument names as they appear in the SOURCE code, ordered, and lazyly populated + * Used to do formal binding + */ + private String[] m_argumentNamesLazy = null; + + final Method method; + + public AjAttributeMethodStruct(Method method, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) { + super(type, sourceContext, messageHandler); + this.method = method; + } + + public String[] getArgumentNames() { + if (m_argumentNamesLazy == null) { + m_argumentNamesLazy = getMethodArgumentNamesAsInSource(method); + } + return m_argumentNamesLazy; + } + } + + /** + * A struct when we read @AJ on field + * + * @author Alexandre Vasseur + */ + private static class AjAttributeFieldStruct extends AjAttributeStruct { + + final Field field; + + public AjAttributeFieldStruct(Field field, ResolvedTypeX type, ISourceContext sourceContext, IMessageHandler messageHandler) { + super(type, sourceContext, messageHandler); + this.field = field; + } + } + + /** + * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones. + * + * @param attribute + * @return + */ + public static boolean acceptAttribute(Attribute attribute) { + return (attribute instanceof RuntimeVisibleAnnotations); + } + + /** + * Extract class level annotations and turn them into AjAttributes. + * + * @param javaClass + * @param type + * @param context + * @param msgHandler + * @return list of AjAttributes + */ + public static List readAj5ClassAttributes(JavaClass javaClass, ResolvedTypeX type, ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) { + AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler); + Attribute[] attributes = javaClass.getAttributes(); + boolean hasAtAspectAnnotation = false; + boolean hasAtPrecedenceAnnotation = false; + + for (int i = 0; i < attributes.length; i++) { + Attribute attribute = attributes[i]; + if (acceptAttribute(attribute)) { + RuntimeAnnotations rvs = (RuntimeAnnotations) attribute; + // we don't need to look for several attribute occurence since it cannot happen as per JSR175 + if (!isCodeStyleAspect) { + hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct); + } + //TODO: below means mix style for @DeclarePrecedence - are we sure we want that ? + hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct); + // there can only be one RuntimeVisible bytecode attribute + break; + } + } + + // basic semantic check + //FIXME AV TBD could be skipped and silently ignore - TBD with Andy + if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) { + msgHandler.handleMessage( + new Message( + "Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'", + IMessage.WARNING, + null, + type.getSourceLocation() + ) + ); + // bypass what we have read + return EMPTY_LIST; + } + //FIXME turn on when ajcMightHaveAspect fixed +// if (hasAtAspectAnnotation && type.isInterface()) { +// msgHandler.handleMessage( +// new Message( +// "Found @Aspect on an interface type '" + type.getName() + "'", +// IMessage.WARNING, +// null, +// type.getSourceLocation() +// ) +// ); +// // bypass what we have read +// return EMPTY_LIST; +// } + + // the following block will not detect @Pointcut in non @Aspect types for optimization purpose + // FIXME AV TBD with Andy + if (!hasAtAspectAnnotation) { + return EMPTY_LIST; + } + + // code style pointcuts are class attributes + // we need to gather the @AJ pointcut right now and not at method level annotation extraction time + // in order to be able to resolve the pointcut references later on + //FIXME alex loop over class super class + //FIXME alex can that be too slow ? + for (int i = 0; i < javaClass.getMethods().length; i++) { + Method method = javaClass.getMethods()[i]; + if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc... + //FIXME alex optimize, this method struct will gets recreated for advice extraction + AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, type, context, msgHandler); + Attribute[] mattributes = method.getAttributes(); + + for (int j = 0; j < mattributes.length; j++) { + Attribute mattribute = mattributes[j]; + if (acceptAttribute(mattribute)) { + RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute; + handlePointcutAnnotation(mrvs, mstruct); + // there can only be one RuntimeVisible bytecode attribute + break; + } + } + struct.ajAttributes.addAll(mstruct.ajAttributes); + } + + + // code style declare error / warning are class attributes + for (int i = 0; i < javaClass.getFields().length; i++) { + Field field = javaClass.getFields()[i]; + if (field.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc... + //FIXME alex optimize, this method struct will gets recreated for advice extraction + AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, type, context, msgHandler); + Attribute[] fattributes = field.getAttributes(); + + for (int j = 0; j < fattributes.length; j++) { + Attribute fattribute = fattributes[j]; + if (acceptAttribute(fattribute)) { + RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute; + if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct)) { + // semantic check - must be in an @Aspect [remove if previous block bypassed in advance] + if (!type.isAnnotationStyleAspect()) { + msgHandler.handleMessage( + new Message( + "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'", + IMessage.WARNING, + null, + type.getSourceLocation() + ) + ); + ;// go ahead + } + } + // there can only be one RuntimeVisible bytecode attribute + break; + } + } + struct.ajAttributes.addAll(fstruct.ajAttributes); + } + return struct.ajAttributes; + } + + /** + * Extract method level annotations and turn them into AjAttributes. + * + * @param method + * @param type + * @param context + * @param msgHandler + * @return list of AjAttributes + */ + public static List readAj5MethodAttributes(Method method, ResolvedTypeX type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) { + if (method.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc... + + AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, type, context, msgHandler); + Attribute[] attributes = method.getAttributes(); + + // we remember if we found one @AJ annotation for minimal semantic error reporting + // the real reporting beeing done thru AJDT and the compiler mapping @AJ to AjAtttribute + // or thru APT + // FIXME AV we could actually skip the whole thing if type is not itself an @Aspect + // but then we would not see any warning. TBD with Andy + boolean hasAtAspectJAnnotation = false; + boolean hasAtAspectJAnnotationMustReturnVoid = false; + for (int i = 0; i < attributes.length; i++) { + Attribute attribute = attributes[i]; + if (acceptAttribute(attribute)) { + RuntimeAnnotations rvs = (RuntimeAnnotations) attribute; + hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation( + rvs, struct, preResolvedPointcut + ); + hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation( + rvs, struct, preResolvedPointcut + ); + hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation( + rvs, struct, preResolvedPointcut + ); + hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation( + rvs, struct, preResolvedPointcut + ); + hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation( + rvs, struct, preResolvedPointcut + ); + // there can only be one RuntimeVisible bytecode attribute + break; + } + } + hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid; + + // semantic check - must be in an @Aspect [remove if previous block bypassed in advance] + if (hasAtAspectJAnnotation && !type.isAnnotationStyleAspect()) { + msgHandler.handleMessage( + new Message( + "Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'", + IMessage.WARNING, + null, + type.getSourceLocation() + ) + ); + ;// go ahead + } + // semantic check - advice must be public + if (hasAtAspectJAnnotation && !struct.method.isPublic()) { + msgHandler.handleMessage( + new Message( + "Found @AspectJ annotation on a non public advice '" + methodToString(struct.method) + "'", + IMessage.ERROR, + null, + type.getSourceLocation() + ) + ); + ;// go ahead + } + // semantic check for non around advice must return void + if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) { + msgHandler.handleMessage( + new Message( + "Found @AspectJ annotation on a non around advice not returning void '" + methodToString( + struct.method + ) + "'", + IMessage.ERROR, + null, + type.getSourceLocation() + ) + ); + ;// go ahead + } + + + return struct.ajAttributes; + } + + /** + * Extract field level annotations and turn them into AjAttributes. + * + * @param field + * @param type + * @param context + * @param msgHandler + * @return list of AjAttributes, always empty for now + */ + public static List readAj5FieldAttributes(Field field, ResolvedTypeX type, ISourceContext context, IMessageHandler msgHandler) { + return Collections.EMPTY_LIST; + } + + /** + * Read @Aspect + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handleAspectAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) { + Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.ASPECT_ANNOTATION); + if (aspect != null) { + ElementNameValuePair aspectPerClause = getAnnotationElement(aspect, VALUE); + final PerClause perClause; + if (aspectPerClause == null) { + // defaults to singleton + perClause = new PerSingleton(); + } else { + String perX = aspectPerClause.getValue().stringifyValue(); + if (perX == null || perX.length() <= 0) { + perClause = new PerSingleton(); + } else { + perClause = parsePerClausePointcut(perX, struct); + } + } + if (perClause == null) { + // could not parse it, ignore the aspect + return false; + } else { + perClause.setLocation(struct.context, -1, -1); + struct.ajAttributes.add(new AjAttribute.Aspect(perClause)); + return true; + } + } + return false; + } + + /** + * Read a perClause, returns null on failure and issue messages + * + * @param perClauseString like "pertarget(.....)" + * @param struct for which we are parsing the per clause + * @return a PerClause instance + */ + private static PerClause parsePerClausePointcut(String perClauseString, AjAttributeStruct struct) { + final String pointcutString; + Pointcut poincut = null; + TypePattern typePattern = null; + final PerClause perClause; + if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) { + pointcutString = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClauseString); + poincut = parsePointcut(pointcutString, struct); + perClause = new PerCflow(poincut, false); + } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) { + pointcutString = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClauseString); + poincut = parsePointcut(pointcutString, struct); + perClause = new PerCflow(poincut, true); + } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) { + pointcutString = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClauseString); + poincut = parsePointcut(pointcutString, struct); + perClause = new PerObject(poincut, false); + } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) { + pointcutString = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClauseString); + poincut = parsePointcut(pointcutString, struct); + perClause = new PerObject(poincut, true); + } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) { + pointcutString = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClauseString); + typePattern = parseTypePattern(pointcutString, struct); + perClause = new PerTypeWithin(typePattern); + } else if (perClauseString.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) { + perClause = new PerSingleton(); + } else { + // could not parse the @AJ perclause - fallback to singleton and issue an error + reportError("@Aspect per clause cannot be read '" + perClauseString + "'", struct); + return null; + } + + if (!PerClause.SINGLETON.equals(perClause.getKind()) + && !PerClause.PERTYPEWITHIN.equals(perClause.getKind()) + && poincut == null) { + // we could not parse the pointcut + return null; + } + if (PerClause.PERTYPEWITHIN.equals(perClause.getKind()) && typePattern == null) { + // we could not parse the type pattern + return null; + } + return perClause; + } + + /** + * Read @DeclarePrecedence + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handlePrecedenceAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) { + Annotation aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPRECEDENCE_ANNOTATION); + if (aspect != null) { + ElementNameValuePair precedence = getAnnotationElement(aspect, VALUE); + if (precedence != null) { + String precedencePattern = precedence.getValue().stringifyValue(); + PatternParser parser = new PatternParser(precedencePattern); + DeclarePrecedence ajPrecedence = parser.parseDominates(); + struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence)); + return true; + } + } + return false; + } + + /** + * Read @Before + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + Annotation before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION); + if (before != null) { + ElementNameValuePair beforeAdvice = getAnnotationElement(before, VALUE); + if (beforeAdvice != null) { + // this/target/args binding + FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; + try { + bindings = extractBindings(struct); + } catch (UnreadableDebugInfoException unreadableDebugInfoException) { + return false; + } + IScope binding = new BindingScope( + struct.enclosingType, + bindings + ); + + // joinpoint, staticJoinpoint binding + int extraArgument = extractExtraArgument(struct.method); + + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct); + if (pc == null) return false;//parse error + pc.resolve(binding); + } + setIgnoreUnboundBindingNames(pc, bindings); + + struct.ajAttributes.add( + new AjAttribute.AdviceAttribute( + AdviceKind.Before, + pc, + extraArgument, + -1, + -1, + struct.context + ) + ); + return true; + } + } + return false; + } + + /** + * Read @After + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTER_ANNOTATION); + if (after != null) { + ElementNameValuePair afterAdvice = getAnnotationElement(after, VALUE); + if (afterAdvice != null) { + // this/target/args binding + FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; + try { + bindings = extractBindings(struct); + } catch (UnreadableDebugInfoException unreadableDebugInfoException) { + return false; + } + IScope binding = new BindingScope( + struct.enclosingType, + bindings + ); + + // joinpoint, staticJoinpoint binding + int extraArgument = extractExtraArgument(struct.method); + + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = parsePointcut(afterAdvice.getValue().stringifyValue(), struct); + if (pc == null) return false;//parse error + pc.resolve(binding); + } + setIgnoreUnboundBindingNames(pc, bindings); + + struct.ajAttributes.add( + new AjAttribute.AdviceAttribute( + AdviceKind.After, + pc, + extraArgument, + -1, + -1, + struct.context + ) + ); + return true; + } + } + return false; + } + + /** + * Read @AfterReturning + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION); + if (after != null) { + ElementNameValuePair annValue = getAnnotationElement(after, VALUE); + ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT); + ElementNameValuePair annReturned = getAnnotationElement(after, RETURNING); + + // extract the pointcut and returned type/binding - do some checks + String pointcut = null; + String returned = null; + if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) { + reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct); + return false; + } + if (annValue != null) { + pointcut = annValue.getValue().stringifyValue(); + } else { + pointcut = annPointcut.getValue().stringifyValue(); + } + if (isNullOrEmpty(pointcut)) { + reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct); + return false; + } + if (annReturned != null) { + returned = annReturned.getValue().stringifyValue(); + if (isNullOrEmpty(returned)) + returned = null; + } + + // this/target/args binding + // exclude the return binding from the pointcut binding since it is an extraArg binding + FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; + try { + bindings = (returned == null ? extractBindings(struct) : extractBindings(struct, returned)); + } catch (UnreadableDebugInfoException unreadableDebugInfoException) { + return false; + } + IScope binding = new BindingScope( + struct.enclosingType, + bindings + ); + + // joinpoint, staticJoinpoint binding + int extraArgument = extractExtraArgument(struct.method); + + // return binding + if (returned != null) { + extraArgument |= Advice.ExtraArgument; + } + + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = parsePointcut(pointcut, struct); + if (pc == null) return false;//parse error + pc.resolve(binding); + } + setIgnoreUnboundBindingNames(pc, bindings); + + struct.ajAttributes.add( + new AjAttribute.AdviceAttribute( + AdviceKind.AfterReturning, + pc, + extraArgument, + -1, + -1, + struct.context + ) + ); + return true; + } + return false; + } + + /** + * Read @AfterThrowing + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION); + if (after != null) { + ElementNameValuePair annValue = getAnnotationElement(after, VALUE); + ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT); + ElementNameValuePair annThrowned = getAnnotationElement(after, THROWING); + + // extract the pointcut and throwned type/binding - do some checks + String pointcut = null; + String throwned = null; + if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) { + reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct); + return false; + } + if (annValue != null) { + pointcut = annValue.getValue().stringifyValue(); + } else { + pointcut = annPointcut.getValue().stringifyValue(); + } + if (isNullOrEmpty(pointcut)) { + reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct); + return false; + } + if (annThrowned != null) { + throwned = annThrowned.getValue().stringifyValue(); + if (isNullOrEmpty(throwned)) + throwned = null; + } + + // this/target/args binding + // exclude the throwned binding from the pointcut binding since it is an extraArg binding + FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; + try { + bindings = (throwned == null ? extractBindings(struct) : extractBindings(struct, throwned)); + } catch (UnreadableDebugInfoException unreadableDebugInfoException) { + return false; + } + IScope binding = new BindingScope( + struct.enclosingType, + bindings + ); + + // joinpoint, staticJoinpoint binding + int extraArgument = extractExtraArgument(struct.method); + + // return binding + if (throwned != null) { + extraArgument |= Advice.ExtraArgument; + } + + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = parsePointcut(pointcut, struct); + if (pc == null) return false;//parse error + pc.resolve(binding); + } + setIgnoreUnboundBindingNames(pc, bindings); + + struct.ajAttributes.add( + new AjAttribute.AdviceAttribute( + AdviceKind.AfterThrowing, + pc, + extraArgument, + -1, + -1, + struct.context + ) + ); + return true; + } + return false; + } + + /** + * Read @Around + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + Annotation around = getAnnotation(runtimeAnnotations, AjcMemberMaker.AROUND_ANNOTATION); + if (around != null) { + ElementNameValuePair aroundAdvice = getAnnotationElement(around, VALUE); + if (aroundAdvice != null) { + // this/target/args binding + FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; + try { + bindings = extractBindings(struct); + } catch (UnreadableDebugInfoException unreadableDebugInfoException) { + return false; + } + IScope binding = new BindingScope( + struct.enclosingType, + bindings + ); + + // joinpoint, staticJoinpoint binding + int extraArgument = extractExtraArgument(struct.method); + + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = parsePointcut(aroundAdvice.getValue().stringifyValue(), struct); + if (pc == null) return false;//parse error + pc.resolve(binding); + } + setIgnoreUnboundBindingNames(pc, bindings); + + struct.ajAttributes.add( + new AjAttribute.AdviceAttribute( + AdviceKind.Around, + pc, + extraArgument, + -1, + -1, + struct.context + ) + ); + return true; + } + } + return false; + } + + /** + * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references + * + * @param runtimeAnnotations + * @param struct + */ + private static void handlePointcutAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { + Annotation pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION); + if (pointcut != null) { + ElementNameValuePair pointcutExpr = getAnnotationElement(pointcut, VALUE); + if (pointcutExpr != null) { + + // semantic check: the method must return void + if (!Type.VOID.equals(struct.method.getReturnType())) { + reportWarning("Found @Pointcut on a method not returning void", struct); + ;//no need to stop + } + // semantic check: the method must not throw anything + if (struct.method.getExceptionTable() != null) { + reportWarning("Found @Pointcut on a method throwing exception", struct); + ;// no need to stop + } + + // this/target/args binding + final IScope binding; + try { + binding = new BindingScope( + struct.enclosingType, + extractBindings(struct) + ); + } catch (UnreadableDebugInfoException e) { + return; + } + + TypeX[] argumentTypes = new TypeX[struct.method.getArgumentTypes().length]; + for (int i = 0; i < argumentTypes.length; i++) { + argumentTypes[i] = TypeX.forSignature(struct.method.getArgumentTypes()[i].getSignature()); + } + + // use a LazyResolvedPointcutDefinition so that the pointcut is resolved lazily + // since for it to be resolved, we will need other pointcuts to be registered as well + Pointcut pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct); + if (pc == null) return;//parse error + // do not resolve binding now but lazily + pc.setLocation(struct.context, -1, -1); + struct.ajAttributes.add( + new AjAttribute.PointcutDeclarationAttribute( + new LazyResolvedPointcutDefinition( + struct.enclosingType, + struct.method.getModifiers(), + struct.method.getName(), + argumentTypes, + pc, + binding + ) + ) + ); + } + } + } + + /** + * Read @DeclareError, @DeclareWarning + * + * @param runtimeAnnotations + * @param struct + * @return true if found + */ + private static boolean handleDeclareErrorOrWarningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) { + Annotation error = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREERROR_ANNOTATION); + boolean hasError = false; + if (error != null) { + ElementNameValuePair declareError = getAnnotationElement(error, VALUE); + if (declareError != null) { + if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) { + reportError("@DeclareError used on a non String constant field", struct); + return false; + } + FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; + IScope binding = new BindingScope( + struct.enclosingType, + bindings + ); + Pointcut pc = parsePointcut(declareError.getValue().stringifyValue(), struct); + if (pc == null) { + hasError = false;//cannot parse pointcut + } else { + pc .resolve(binding); + DeclareErrorOrWarning deow = new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString()); + deow.setLocation(struct.context, -1, -1); + struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow)); + hasError = true; + } + } + } + Annotation warning = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREWARNING_ANNOTATION); + boolean hasWarning = false; + if (warning != null) { + ElementNameValuePair declareWarning = getAnnotationElement(warning, VALUE); + if (declareWarning != null) { + if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) { + reportError("@DeclareWarning used on a non String constant field", struct); + return false; + } + FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; + IScope binding = new BindingScope( + struct.enclosingType, + bindings + ); + Pointcut pc = parsePointcut(declareWarning.getValue().stringifyValue(), struct); + if (pc == null) { + hasWarning = false;//cannot parse pointcut + } else { + pc.resolve(binding); + DeclareErrorOrWarning deow = new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString()); + deow.setLocation(struct.context, -1, -1); + struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow)); + return hasWarning = true; + } + } + } + return hasError || hasWarning; + } + + /** + * Returns a readable representation of a method. + * Method.toString() is not suitable. + * + * @param method + * @return + */ + private static String methodToString(Method method) { + StringBuffer sb = new StringBuffer(); + sb.append(method.getName()); + sb.append(method.getSignature()); + return sb.toString(); + } + + /** + * Returns a readable representation of a field. + * Field.toString() is not suitable. + * + * @param field + * @return + */ + private static String fieldToString(Field field) { + StringBuffer sb = new StringBuffer(); + sb.append(field.getName()).append(' '); + sb.append(field.getSignature()); + return sb.toString(); + } + + /** + * Build the bindings for a given method (pointcut / advice) + * + * @param struct + * @return null if no debug info is available + */ + private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct) + throws UnreadableDebugInfoException { + Method method = struct.method; + String[] argumentNames = struct.getArgumentNames(); + + // assert debug info was here + if (argumentNames.length != method.getArgumentTypes().length) { + reportError("Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '' in Ant)", struct); + throw new UnreadableDebugInfoException(); + } + + List bindings = new ArrayList(); + for (int i = 0; i < argumentNames.length; i++) { + String argumentName = argumentNames[i]; + TypeX argumentType = TypeX.forSignature(method.getArgumentTypes()[i].getSignature()); + + // do not bind JoinPoint / StaticJoinPoint / EnclosingStaticJoinPoint + // TODO solve me : this means that the JP/SJP/ESJP cannot appear as binding + // f.e. when applying advice on advice etc + if ((AjcMemberMaker.TYPEX_JOINPOINT.equals(argumentType) + || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.equals(argumentType) + || AjcMemberMaker.TYPEX_STATICJOINPOINT.equals(argumentType) + || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType) + || AjcMemberMaker.AROUND_CLOSURE_TYPE.equals(argumentType))) { + //continue;// skip + bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i)); + } else { + bindings.add(new FormalBinding(argumentType, argumentName, i)); + } + } + + return (FormalBinding[]) bindings.toArray(new FormalBinding[]{}); + } + + //FIXME alex deal with exclude index + private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal) + throws UnreadableDebugInfoException { + FormalBinding[] bindings = extractBindings(struct); + int excludeIndex = -1; + for (int i = 0; i < bindings.length; i++) { + FormalBinding binding = bindings[i]; + if (binding.getName().equals(excludeFormal)) { + excludeIndex = i; + bindings[i] = new FormalBinding.ImplicitFormalBinding( + binding.getType(), binding.getName(), binding.getIndex() + ); + break; + } + } + return bindings; +// +// if (excludeIndex >= 0) { +// FormalBinding[] bindingsFiltered = new FormalBinding[bindings.length-1]; +// int k = 0; +// for (int i = 0; i < bindings.length; i++) { +// if (i == excludeIndex) { +// ; +// } else { +// bindingsFiltered[k] = new FormalBinding(bindings[i].getType(), bindings[i].getName(), k); +// k++; +// } +// } +// return bindingsFiltered; +// } else { +// return bindings; +// } + } + + + /** + * Compute the flag for the xxxJoinPoint extra argument + * + * @param method + * @return + */ + private static int extractExtraArgument(Method method) { + int extraArgument = 0; + Type[] methodArgs = method.getArgumentTypes(); + for (int i = 0; i < methodArgs.length; i++) { + String methodArg = methodArgs[i].getSignature(); + if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(methodArg)) { + extraArgument |= Advice.ThisJoinPoint; + } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(methodArg)) { + extraArgument |= Advice.ThisJoinPoint; + } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(methodArg)) { + extraArgument |= Advice.ThisJoinPointStaticPart; + } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(methodArg)) { + extraArgument |= Advice.ThisEnclosingJoinPointStaticPart; + } + } + return extraArgument; + } + + /** + * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation + * + * @param rvs + * @param annotationType + * @return + */ + private static Annotation getAnnotation(RuntimeAnnotations rvs, TypeX annotationType) { + final String annotationTypeName = annotationType.getName(); + for (Iterator iterator = rvs.getAnnotations().iterator(); iterator.hasNext();) { + Annotation rv = (Annotation) iterator.next(); + if (annotationTypeName.equals(rv.getTypeName())) { + return rv; + } + } + return null; + } + + /** + * Returns the value of a given element of an annotation or null if not found + * Caution: Does not handles default value. + * + * @param annotation + * @param elementName + * @return + */ + private static ElementNameValuePair getAnnotationElement(Annotation annotation, String elementName) { + for (Iterator iterator1 = annotation.getValues().iterator(); iterator1.hasNext();) { + ElementNameValuePair element = (ElementNameValuePair) iterator1.next(); + if (elementName.equals(element.getNameString())) { + return element; + } + } + return null; + } + + /** + * Extract the method argument names as in source from debug info + * returns an empty array upon inconsistency + * + * @param method + * @return + */ + private static String[] getMethodArgumentNamesAsInSource(Method method) { + if (method.getArgumentTypes().length == 0) { + return EMPTY_STRINGS; + } + + final int startAtStackIndex = method.isStatic() ? 0 : 1; + final List arguments = new ArrayList(); + LocalVariableTable lt = (LocalVariableTable) method.getLocalVariableTable(); + if (lt != null) { + for (int j = 0; j < lt.getLocalVariableTable().length; j++) { + LocalVariable localVariable = lt.getLocalVariableTable()[j]; + if (localVariable.getStartPC() == 0) { + if (localVariable.getIndex() >= startAtStackIndex) { + arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex())); + } + } + } + } + + if (arguments.size() != method.getArgumentTypes().length) { + return EMPTY_STRINGS; + } + + // sort by index + Collections.sort( + arguments, new Comparator() { + public int compare(Object o, Object o1) { + MethodArgument mo = (MethodArgument) o; + MethodArgument mo1 = (MethodArgument) o1; + if (mo.indexOnStack == mo1.indexOnStack) { + return 0; + } else if (mo.indexOnStack > mo1.indexOnStack) { + return 1; + } else { + return -1; + } + } + } + ); + String[] argumentNames = new String[arguments.size()]; + int i = 0; + for (Iterator iterator = arguments.iterator(); iterator.hasNext(); i++) { + MethodArgument methodArgument = (MethodArgument) iterator.next(); + argumentNames[i] = methodArgument.name; + } + return argumentNames; + } + + /** + * A method argument, used for sorting by indexOnStack (ie order in signature) + * + * @author Alexandre Vasseur + */ + private static class MethodArgument { + String name; + int indexOnStack; + + public MethodArgument(String name, int indexOnStack) { + this.name = name; + this.indexOnStack = indexOnStack; + } + } + + /** + * BindingScope that knows the enclosingType, which is needed for pointcut reference resolution + * + * @author Alexandre Vasseur + */ + public static class BindingScope extends SimpleScope { + private ResolvedTypeX m_enclosingType; + + public BindingScope(ResolvedTypeX type, FormalBinding[] bindings) { + super(type.getWorld(), bindings); + m_enclosingType = type; + } + + public ResolvedTypeX getEnclosingType() { + return m_enclosingType; + } + } + + /** + * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all + * pointcut referenced before pointcut resolution happens + * + * @author Alexandre Vasseur + */ + public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition { + private Pointcut m_pointcutUnresolved; + private IScope m_binding; + + private Pointcut m_lazyPointcut = null; + + public LazyResolvedPointcutDefinition(ResolvedTypeX declaringType, int modifiers, String name, TypeX[] parameterTypes, + Pointcut pointcut, IScope binding) { + super(declaringType, modifiers, name, parameterTypes, null); + m_pointcutUnresolved = pointcut; + m_binding = binding; + } + + public Pointcut getPointcut() { + if (m_lazyPointcut == null) { + m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding); + m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved); + } + return m_lazyPointcut; + } + } + + /** + * Helper to test empty strings + * + * @param s + * @return + */ + private static boolean isNullOrEmpty(String s) { + return (s == null || s.length() <= 0); + } + + /** + * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind + * xxxJoinPoint for @AJ advices + * + * @param pointcut + * @param bindings + */ + private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) { + // register ImplicitBindings as to be ignored since unbound + // TODO is it likely to fail in a bad way if f.e. this(jp) etc ? + List ignores = new ArrayList(); + for (int i = 0; i < bindings.length; i++) { + FormalBinding formalBinding = bindings[i]; + if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) { + ignores.add(formalBinding.getName()); + } + } + pointcut.m_ignoreUnboundBindingForNames = (String[]) ignores.toArray(new String[ignores.size()]); + } + + /** + * A check exception when we cannot read debug info (needed for formal binding) + */ + private static class UnreadableDebugInfoException extends Exception { + } + + /** + * Report an error + * + * @param message + * @param location + */ + private static void reportError(String message, AjAttributeStruct location) { + if (!location.handler.isIgnoring(IMessage.ERROR)) { + location.handler.handleMessage( + new Message( + message, + location.enclosingType.getSourceLocation(), + true + ) + ); + } + } + + /** + * Report a warning + * + * @param message + * @param location + */ + private static void reportWarning(String message, AjAttributeStruct location) { + if (!location.handler.isIgnoring(IMessage.WARNING)) { + location.handler.handleMessage( + new Message( + message, + location.enclosingType.getSourceLocation(), + false + ) + ); + } + } + + /** + * Parse the given pointcut, return null on failure and issue an error + * + * @param pointcutString + * @param location + * @return + */ + private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct location) { + try { + Pointcut pointcut = Pointcut.fromString(pointcutString); + pointcut.setLocation(location.context, -1, -1);//FIXME -1,-1 is not good enough + return pointcut; + } catch (ParserException e) { + reportError("Invalid pointcut '" + pointcutString + "' : " + e.getLocation(), location); + return null; + } + } + + /** + * Parse the given type pattern, return null on failure and issue an error + * + * @param patternString + * @param location + * @return + */ + private static TypePattern parseTypePattern(String patternString, AjAttributeStruct location) { + try { + TypePattern typePattern = new PatternParser(patternString).parseTypePattern(); + typePattern.setLocation(location.context, -1, -1);//FIXME -1,-1 is not good enough + return typePattern; + } catch (ParserException e) { + reportError("Invalid type pattern'" + patternString + "' : " + e.getLocation(), location); + return null; + } + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java b/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java index 1fa87d1b0..3dc487853 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java @@ -37,7 +37,6 @@ import org.aspectj.weaver.TypeX; import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.World; import org.aspectj.weaver.PerObjectInterfaceTypeMunger; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; import org.aspectj.weaver.ast.Literal; import org.aspectj.weaver.ast.Test; import org.aspectj.weaver.patterns.ExactTypePattern; @@ -362,7 +361,7 @@ public class BcelAdvice extends Advice { if (v == null) { // if not @AJ aspect, go on with the regular binding handling - if (!Ajc5MemberMaker.isAnnotationStyleAspect(getConcreteAspect())) { + if (!getConcreteAspect().isAnnotationStyleAspect()) { continue; } else { // ATAJ: for @AJ aspects, handle implicit binding of xxJoinPoint @@ -408,7 +407,7 @@ public class BcelAdvice extends Advice { // ATAJ: for code style aspect, handles the extraFlag as usual ie not // in the middle of the formal bindings but at the end, in a rock solid ordering - if (!Ajc5MemberMaker.isAnnotationStyleAspect(getConcreteAspect())) { + if (!getConcreteAspect().isAnnotationStyleAspect()) { if (getKind() == AdviceKind.Around) { il.append(closureInstantiation); } else if (hasExtraParameter()) { diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelField.java b/weaver/src/org/aspectj/weaver/bcel/BcelField.java index ee8d51bc5..98789df08 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelField.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelField.java @@ -27,7 +27,6 @@ import org.aspectj.weaver.ResolvedMember; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.TypeX; import org.aspectj.weaver.World; -import org.aspectj.weaver.ataspectj.Aj5Attributes; final class BcelField extends ResolvedMember { @@ -56,7 +55,7 @@ final class BcelField extends ResolvedMember { private void unpackAttributes(World world) { Attribute[] attrs = field.getAttributes(); List as = BcelAttributes.readAjAttributes(getDeclaringType().getClassName(),attrs, getSourceContext(world),world.getMessageHandler()); - as.addAll(Aj5Attributes.readAj5FieldAttributes(field, world.resolve(getDeclaringType()), getSourceContext(world), world.getMessageHandler())); + as.addAll(AtAjAttributes.readAj5FieldAttributes(field, world.resolve(getDeclaringType()), getSourceContext(world), world.getMessageHandler())); for (Iterator iter = as.iterator(); iter.hasNext();) { AjAttribute a = (AjAttribute) iter.next(); diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java b/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java index a8c629992..ca4dfaaa4 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java @@ -34,7 +34,6 @@ import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.ShadowMunger; import org.aspectj.weaver.TypeX; import org.aspectj.weaver.World; -import org.aspectj.weaver.ataspectj.Aj5Attributes; final class BcelMethod extends ResolvedMember { @@ -101,7 +100,7 @@ final class BcelMethod extends ResolvedMember { associatedShadowMunger = null; List as = BcelAttributes.readAjAttributes(getDeclaringType().getClassName(),method.getAttributes(), getSourceContext(world),world.getMessageHandler()); processAttributes(world, as); - as = Aj5Attributes.readAj5MethodAttributes(method, world.resolve(getDeclaringType()), preResolvedPointcut,getSourceContext(world), world.getMessageHandler()); + as = AtAjAttributes.readAj5MethodAttributes(method, world.resolve(getDeclaringType()), preResolvedPointcut,getSourceContext(world), world.getMessageHandler()); processAttributes(world,as); } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java index 862b2a65b..75c46d5dd 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java @@ -36,9 +36,8 @@ import org.aspectj.weaver.ResolvedPointcutDefinition; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.TypeX; import org.aspectj.weaver.WeaverStateInfo; +import org.aspectj.weaver.AjcMemberMaker; import org.aspectj.weaver.patterns.PerClause; -import org.aspectj.weaver.ataspectj.Aj5Attributes; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; // ??? exposed for testing @@ -186,7 +185,7 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { public boolean isAnnotationStyleAspect() { if (!discoveredWhetherAnnotationStyle) { discoveredWhetherAnnotationStyle = true; - isAnnotationStyleAspect = !isCodeStyleAspect && hasAnnotation(Ajc5MemberMaker.ASPECT); + isAnnotationStyleAspect = !isCodeStyleAspect && hasAnnotation(AjcMemberMaker.ASPECT_ANNOTATION); } return isAnnotationStyleAspect; } @@ -198,7 +197,7 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { // Pass in empty list that can store things for readAj5 to process List l = BcelAttributes.readAjAttributes(javaClass.getClassName(),javaClass.getAttributes(), getResolvedTypeX().getSourceContext(),getResolvedTypeX().getWorld().getMessageHandler()); processAttributes(l,pointcuts,false); - l = Aj5Attributes.readAj5ClassAttributes(javaClass, getResolvedTypeX(), getResolvedTypeX().getSourceContext(), getResolvedTypeX().getWorld().getMessageHandler(),isCodeStyleAspect); + l = AtAjAttributes.readAj5ClassAttributes(javaClass, getResolvedTypeX(), getResolvedTypeX().getSourceContext(), getResolvedTypeX().getWorld().getMessageHandler(),isCodeStyleAspect); processAttributes(l,pointcuts,true); this.pointcuts = (ResolvedPointcutDefinition[]) diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index f41cce965..4bc3daf92 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -74,7 +74,6 @@ import org.aspectj.weaver.TypeX; import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.World; import org.aspectj.weaver.ast.Var; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; /* @@ -2549,8 +2548,7 @@ public class BcelShadow extends Shadow { } // ATAJ for @AJ aspect we need to link the closure with the joinpoint instance - if (Ajc5MemberMaker.isAnnotationStyleAspect(munger.getConcreteAspect())) { - //advice.append(new POP()); + if (munger.getConcreteAspect().isAnnotationStyleAspect()) { closureInstantiation.append(Utility.createInvoke( getFactory(), getWorld(), @@ -2563,12 +2561,9 @@ public class BcelShadow extends Shadow { ) )); } - //System.err.println(closureInstantiation); - InstructionList advice = new InstructionList(); advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation)); -// advice.append(closureInstantiation); // invoke the advice advice.append(munger.getNonTestAdviceInstructions(this)); diff --git a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java index f9d97a936..73eef47d7 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java @@ -35,7 +35,6 @@ import org.aspectj.weaver.TypeX; import org.aspectj.weaver.VersionedDataInputStream; import org.aspectj.weaver.World; import org.aspectj.weaver.bcel.BcelAccessForInlineMunger; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; import org.aspectj.weaver.ast.Expr; import org.aspectj.weaver.ast.Test; @@ -106,7 +105,7 @@ public class PerCflow extends PerClause { } //ATAJ inline around advice support - don't use a late munger to allow around inling for itself - if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) { + if (inAspect.isAnnotationStyleAspect()) { inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect)); } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerObject.java b/weaver/src/org/aspectj/weaver/patterns/PerObject.java index 3ec3addeb..31eef9ade 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerObject.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerObject.java @@ -30,7 +30,6 @@ import org.aspectj.weaver.Shadow; import org.aspectj.weaver.VersionedDataInputStream; import org.aspectj.weaver.World; import org.aspectj.weaver.bcel.BcelAccessForInlineMunger; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; import org.aspectj.weaver.ast.Expr; import org.aspectj.weaver.ast.Test; import org.aspectj.weaver.ast.Var; @@ -119,7 +118,7 @@ public class PerObject extends PerClause { } //ATAJ inline around advice support - don't use a late munger to allow around inling for itself - if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) { + if (inAspect.isAnnotationStyleAspect()) { inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect)); } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java index bf390fa6e..385f9175c 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java @@ -27,7 +27,6 @@ import org.aspectj.weaver.bcel.BcelAccessForInlineMunger; import org.aspectj.weaver.ast.Expr; import org.aspectj.weaver.ast.Literal; import org.aspectj.weaver.ast.Test; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; public class PerSingleton extends PerClause { public PerSingleton() { @@ -97,7 +96,7 @@ public class PerSingleton extends PerClause { ret.inAspect = inAspect; //ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects - if (!inAspect.isAbstract() && Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) { + if (!inAspect.isAbstract() && inAspect.isAnnotationStyleAspect()) { //TODO will those change be ok if we add a serializable aspect ? // dig: "can't be Serializable/Cloneable unless -XserializableAspects" inAspect.crosscuttingMembers.addLateTypeMunger( @@ -106,7 +105,7 @@ public class PerSingleton extends PerClause { } //ATAJ inline around advice support - if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) { + if (inAspect.isAnnotationStyleAspect()) { inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect)); } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java b/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java index 59c4169b7..651d192a3 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java @@ -33,7 +33,6 @@ import org.aspectj.weaver.Shadow; import org.aspectj.weaver.VersionedDataInputStream; import org.aspectj.weaver.World; import org.aspectj.weaver.bcel.BcelAccessForInlineMunger; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; import org.aspectj.weaver.ast.Expr; import org.aspectj.weaver.ast.Literal; import org.aspectj.weaver.ast.Test; @@ -156,7 +155,7 @@ public class PerTypeWithin extends PerClause { } //ATAJ inline around advice support - don't use a late munger to allow around inling for itself - if (Ajc5MemberMaker.isAnnotationStyleAspect(inAspect)) { + if (inAspect.isAnnotationStyleAspect()) { inAspect.crosscuttingMembers.addTypeMunger(new BcelAccessForInlineMunger(inAspect)); } diff --git a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java index a1bf961cd..67bd70f3c 100644 --- a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java +++ b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java @@ -37,7 +37,6 @@ import org.aspectj.util.FileUtil; import org.aspectj.weaver.IClassFileProvider; import org.aspectj.weaver.IWeaveRequestor; import org.aspectj.weaver.ResolvedTypeX; -import org.aspectj.weaver.ataspectj.Ajc5MemberMaker; import org.aspectj.weaver.bcel.BcelWeaver; import org.aspectj.weaver.bcel.BcelWorld; import org.aspectj.weaver.bcel.UnwovenClassFile; @@ -209,7 +208,7 @@ public class WeavingAdaptor { */ private boolean shouldWeaveAspect (String name) { ResolvedTypeX type = bcelWorld.resolve(name); - return (type == null || !type.isAspect() || Ajc5MemberMaker.isAnnotationStyleAspect(type)); + return (type == null || !type.isAspect() || type.isAnnotationStyleAspect()); } /**