diff options
author | avasseur <avasseur> | 2005-04-26 10:52:36 +0000 |
---|---|---|
committer | avasseur <avasseur> | 2005-04-26 10:52:36 +0000 |
commit | 4cf9913a74c804176c04e9cc5effcbea24289418 (patch) | |
tree | 91ec70d29752f5561f8afca1941ae69caf83f058 /weaver | |
parent | 3e1783bc03e372ad8957e5e24e41b5c7d0e7dd26 (diff) | |
download | aspectj-4cf9913a74c804176c04e9cc5effcbea24289418.tar.gz aspectj-4cf9913a74c804176c04e9cc5effcbea24289418.zip |
fix some build. Move AspectJrt5 test to AllTest15. Add weaver checks for @AJ annotations + tests from Andy H
Diffstat (limited to 'weaver')
-rw-r--r-- | weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java | 249 |
1 files changed, 212 insertions, 37 deletions
diff --git a/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java b/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java index 2eb120ecd..290e32f61 100644 --- a/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java +++ b/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java @@ -1,12 +1,13 @@ /******************************************************************************* - * Copyright (c) 2005 Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html + * 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 Jonas Bonér, Alexandre Vasseur + * initial implementation Alexandre Vasseur *******************************************************************************/ package org.aspectj.weaver.ataspectj; @@ -25,9 +26,11 @@ 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; @@ -50,6 +53,7 @@ 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; /** * Annotation defined aspect reader. @@ -124,13 +128,13 @@ public class Aj5Attributes { } /** - * Annotations are RV or RIV for now we don't care + * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones. * * @param attribute * @return */ public static boolean acceptAttribute(Attribute attribute) { - return (attribute instanceof RuntimeAnnotations); + return (attribute instanceof RuntimeVisibleAnnotations); } /** @@ -145,15 +149,58 @@ public class Aj5Attributes { 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; - if (!isCodeStyleAspect) handleAspectAnnotation(rvs, struct); - handlePrecedenceAnnotation(rvs, struct); + // 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 @@ -171,11 +218,12 @@ public class Aj5Attributes { if (acceptAttribute(mattribute)) { RuntimeAnnotations mrvs = (RuntimeAnnotations) mattribute; handlePointcutAnnotation(mrvs, mstruct); + // there can only be one RuntimeVisible bytecode attribute + break; } } struct.ajAttributes.addAll(mstruct.ajAttributes); } - return struct.ajAttributes; } @@ -194,17 +242,66 @@ public class Aj5Attributes { 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; - handleBeforeAnnotation(rvs, struct, preResolvedPointcut); - handleAfterAnnotation(rvs, struct, preResolvedPointcut); - handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut); - handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut); - handleAroundAnnotation(rvs, struct, preResolvedPointcut); + 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; } @@ -227,8 +324,9 @@ public class Aj5Attributes { * * @param runtimeAnnotations * @param struct + * @return true if found */ - private static void handleAspectAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) { + 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"); @@ -237,6 +335,7 @@ public class Aj5Attributes { 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; @@ -247,8 +346,10 @@ public class Aj5Attributes { } clause.setLocation(struct.context, -1, -1); struct.ajAttributes.add(new AjAttribute.Aspect(clause)); + return true; } } + return false; } /** @@ -282,7 +383,7 @@ public class Aj5Attributes { struct.handler.handleMessage( new Message( "cannot read per clause from @Aspect: " + perClause, - null,//TODO + struct.enclosingType.getSourceLocation(), true ) ); @@ -294,8 +395,9 @@ public class Aj5Attributes { * * @param runtimeAnnotations * @param struct + * @return true if found */ - private static void handlePrecedenceAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeStruct struct) { + 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"); @@ -304,8 +406,10 @@ public class Aj5Attributes { PatternParser parser = new PatternParser(precedencePattern); DeclarePrecedence ajPrecedence = parser.parseDominates(); struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence)); + return true; } } + return false; } /** @@ -313,8 +417,9 @@ public class Aj5Attributes { * * @param runtimeAnnotations * @param struct + * @return true if found */ - private static void handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + 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"); @@ -346,8 +451,10 @@ public class Aj5Attributes { struct.context ) ); + return true; } } + return false; } /** @@ -355,8 +462,9 @@ public class Aj5Attributes { * * @param runtimeAnnotations * @param struct + * @return true if found */ - private static void handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + 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"); @@ -388,8 +496,10 @@ public class Aj5Attributes { struct.context ) ); + return true; } } + return false; } /** @@ -397,8 +507,9 @@ public class Aj5Attributes { * * @param runtimeAnnotations * @param struct + * @return true if found */ - private static void handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + 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"); @@ -448,6 +559,7 @@ public class Aj5Attributes { 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, @@ -458,7 +570,9 @@ public class Aj5Attributes { struct.context ) ); + return true; } + return false; } /** @@ -466,8 +580,9 @@ public class Aj5Attributes { * * @param runtimeAnnotations * @param struct + * @return true if found */ - private static void handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + 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"); @@ -527,7 +642,9 @@ public class Aj5Attributes { struct.context ) ); + return true; } + return false; } /** @@ -535,8 +652,9 @@ public class Aj5Attributes { * * @param runtimeAnnotations * @param struct + * @return true if found */ - private static void handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { + 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"); @@ -568,8 +686,10 @@ public class Aj5Attributes { struct.context ) ); + return true; } } + return false; } /** @@ -583,6 +703,34 @@ public class Aj5Attributes { 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 IScope binding = new BindingScope( struct.enclosingType, @@ -596,21 +744,47 @@ public class Aj5Attributes { // 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 - struct.ajAttributes.add(new AjAttribute.PointcutDeclarationAttribute( - new LazyResolvedPointcutDefinition( - struct.enclosingType, - struct.method.getModifiers(), - struct.method.getName(), - argumentTypes, - Pointcut.fromString(pointcutExpr.getValue().stringifyValue()), - binding - ) - )); + 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; + } } } } /** + * 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(); + } + + /** * Build the bindings for a given method (pointcut / advice) * * @param struct @@ -723,14 +897,13 @@ public class Aj5Attributes { /** * Returns the value of a given element of an annotation or null if not found - * Does not handles default value + * Caution: Does not handles default value. * * @param annotation * @param elementName * @return */ private static ElementNameValuePair getAnnotationElement(Annotation annotation, String elementName) { - //FIXME alex does not handles default values which are annotation of elements in the annotation class for (Iterator iterator1 = annotation.getValues().iterator(); iterator1.hasNext();) { ElementNameValuePair element = (ElementNameValuePair) iterator1.next(); if (elementName.equals(element.getNameString())) { @@ -838,16 +1011,18 @@ public class Aj5Attributes { private Pointcut m_lazyPointcut = null; - public LazyResolvedPointcutDefinition(TypeX declaringType, int modifiers, String name, TypeX[] parameterTypes, + 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; } |