aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--aspectj5rt/java5-src/org/aspectj/lang/annotation/control/CodeGenerationHint.java34
-rw-r--r--org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/IfPseudoToken.java103
-rw-r--r--testing/newsrc/org/aspectj/testing/XMLBasedAjcTestCase.java15
-rw-r--r--tests/bugs172/pr398246/Code.java19
-rw-r--r--tests/bugs172/pr398246/Code2.java20
-rw-r--r--tests/bugs172/pr398246/Code3.java21
-rw-r--r--tests/bugs172/pr398246/Code4.java21
-rw-r--r--tests/bugs172/pr398246/CodeExtra4.java11
-rw-r--r--tests/src/org/aspectj/systemtest/ajc172/Ajc172Tests.java32
-rw-r--r--tests/src/org/aspectj/systemtest/ajc172/ajc172.xml51
10 files changed, 306 insertions, 21 deletions
diff --git a/aspectj5rt/java5-src/org/aspectj/lang/annotation/control/CodeGenerationHint.java b/aspectj5rt/java5-src/org/aspectj/lang/annotation/control/CodeGenerationHint.java
new file mode 100644
index 000000000..7fe9dea24
--- /dev/null
+++ b/aspectj5rt/java5-src/org/aspectj/lang/annotation/control/CodeGenerationHint.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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 Andy Clement
+ *******************************************************************************/
+package org.aspectj.lang.annotation.control;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Provide code generation hints to the compiler (e.g. names to use for generated members).
+ *
+ * @author Andy Clement
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.METHOD)
+public @interface CodeGenerationHint {
+
+ /**
+ * Defines the name suffix to use for a generated member representing an if pointcut (prefix will be 'ajc$if$').
+ * If left blank, a suffix will be generated.
+ */
+ String ifNameSuffix() default "";
+
+}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/IfPseudoToken.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/IfPseudoToken.java
index 9bf2f3171..821b8b3be 100644
--- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/IfPseudoToken.java
+++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/IfPseudoToken.java
@@ -14,15 +14,23 @@ package org.aspectj.ajdt.internal.compiler.ast;
import java.lang.reflect.Modifier;
+import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
@@ -35,15 +43,18 @@ import org.aspectj.weaver.patterns.Pointcut;
/**
* (formals*): ... if(expr) ...
*
- * generates the following: public static final boolean ajc$if_N(formals*, [thisJoinPoints as needed]) { return expr; }
+ * generates the following: public static final boolean ajc$if_N(formals*,
+ * [thisJoinPoints as needed]) { return expr; }
*
- * Here's the complicated bit, it deals with cflow: (a): ... this(a) && cflow(if (a == foo)) is an error. The way we capture this
- * is: We generate the ajc$if method with an (a) parameter, we let eclipse do the proper name binding. We then, as a post pass (that
- * we need to do anyway) look for the used parameters. If a is used, we signal an error because a was not one of the cflow
- * variables. XXX we'll do this part after we do cflow
+ * Here's the complicated bit, it deals with cflow: (a): ... this(a) && cflow(if
+ * (a == foo)) is an error. The way we capture this is: We generate the ajc$if
+ * method with an (a) parameter, we let eclipse do the proper name binding. We
+ * then, as a post pass (that we need to do anyway) look for the used
+ * parameters. If a is used, we signal an error because a was not one of the
+ * cflow variables. XXX we'll do this part after we do cflow
*
- * The IfPointcut pcd then generates itself always as a dynamic test, it has to get the right parameters through any named pointcut
- * references...
+ * The IfPointcut pcd then generates itself always as a dynamic test, it has to
+ * get the right parameters through any named pointcut references...
*/
public class IfPseudoToken extends PseudoToken {
public Expression expr;
@@ -61,7 +72,8 @@ public class IfPseudoToken extends PseudoToken {
} else if (expr instanceof TrueLiteral) {
return IfPointcut.makeIfTruePointcut(Pointcut.SYMBOLIC);
} else {
- pointcut = new IfPointcut(new ResolvedMemberImpl(Member.METHOD, UnresolvedType.OBJECT, 0, "if_", "()V"), 0);
+ pointcut = new IfPointcut(new ResolvedMemberImpl(Member.METHOD,
+ UnresolvedType.OBJECT, 0, "if_", "()V"), 0);
}
return pointcut;
@@ -70,33 +82,80 @@ public class IfPseudoToken extends PseudoToken {
/**
* enclosingDec is either AdviceDeclaration or PointcutDeclaration
*/
- public void postParse(TypeDeclaration typeDec, MethodDeclaration enclosingDec) {
+ public void postParse(TypeDeclaration typeDec,
+ MethodDeclaration enclosingDec) {
// typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd,
// "if pcd is not implemented in 1.1alpha1");
// XXX need to implement correctly
if (pointcut == null)
return;
- testMethod = makeIfMethod(enclosingDec.compilationResult, enclosingDec, typeDec);
+ testMethod = makeIfMethod(enclosingDec.compilationResult, enclosingDec,
+ typeDec);
AstUtil.addMethodDeclaration(typeDec, testMethod);
}
+ private final static char[] CodeGenerationHint = "CodeGenerationHint".toCharArray();
+ private final static char[] FullyQualifiedCodeGenerationHint = "org.aspectj.lang.annotation.control.CodeGenerationHint".toCharArray();
+ private final static char[] IfNameSuffix = "ifNameSuffix".toCharArray();
+
// XXX todo: make sure that errors in Arguments only get displayed once
- private MethodDeclaration makeIfMethod(CompilationResult result, MethodDeclaration enclosingDec,
- TypeDeclaration containingTypeDec) {
+ private MethodDeclaration makeIfMethod(CompilationResult result,
+ MethodDeclaration enclosingDec, TypeDeclaration containingTypeDec) {
MethodDeclaration ret = new IfMethodDeclaration(result, pointcut);
- ret.modifiers = ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccPublic;
+ ret.modifiers = ClassFileConstants.AccStatic
+ | ClassFileConstants.AccFinal | ClassFileConstants.AccPublic;
ret.returnType = AstUtil.makeTypeReference(TypeBinding.BOOLEAN);
+
+ String nameSuffix = null;
+
+ if (enclosingDec!=null && enclosingDec.annotations!=null) {
+ NormalAnnotation interestingAnnotation = null;
+ Annotation[] as = enclosingDec.annotations;
+ if (as!=null) {
+ for (int a = 0; a < as.length && interestingAnnotation == null; a++) {
+ if (as[a] instanceof NormalAnnotation) {
+ TypeReference tr = as[a].type;
+ if (tr instanceof SingleTypeReference) {
+ if (CharOperation.equals(CodeGenerationHint,((SingleTypeReference)tr).token)) {
+ interestingAnnotation = (NormalAnnotation)as[a];
+ }
+ } else if (tr instanceof QualifiedTypeReference) {
+ char[] qualifiedName = CharOperation.concatWith(((QualifiedTypeReference)tr).tokens,'.');
+ if (CharOperation.equals(FullyQualifiedCodeGenerationHint,qualifiedName)) {
+ interestingAnnotation = (NormalAnnotation)as[a];
+ }
+ }
+ }
+ }
+ }
+ if (interestingAnnotation!=null) {
+ MemberValuePair[] memberValuePairs = interestingAnnotation.memberValuePairs;
+ for (MemberValuePair memberValuePair: memberValuePairs) {
+ if (CharOperation.equals(IfNameSuffix,memberValuePair.name) && (memberValuePair.value instanceof StringLiteral)) {
+ nameSuffix = new String(((StringLiteral)memberValuePair.value).source());
+ }
+ }
+ }
+ }
+
+
// create a more stable name 277508
StringBuffer ifSelector = new StringBuffer();
ifSelector.append("ajc$if$");
- ifSelector.append(Integer.toHexString(expr.sourceStart));
+ if (nameSuffix == null || nameSuffix.length()==0) {
+ ifSelector.append(Integer.toHexString(expr.sourceStart));
+ } else {
+ ifSelector.append(nameSuffix);
+ }
// possibly even better logic for more reliable name:
// if (enclosingDec instanceof AdviceDeclaration) {
- // // name is ajc$if$<adviceSequenceNumber>$<hashcodeOfIfExpressionInHex>
+ // // name is
+ // ajc$if$<adviceSequenceNumber>$<hashcodeOfIfExpressionInHex>
// ifSelector.append("ajc$if$");
- // ifSelector.append(((AdviceDeclaration) enclosingDec).adviceSequenceNumberInType);
+ // ifSelector.append(((AdviceDeclaration)
+ // enclosingDec).adviceSequenceNumberInType);
// ifSelector.append("$").append(Integer.toHexString(expr.toString().hashCode()));
// } else if (enclosingDec instanceof PointcutDeclaration) {
// // name is pointcut selector then $if$<hashcodeOfIfExpressionInHex>
@@ -104,16 +163,19 @@ public class IfPseudoToken extends PseudoToken {
// ifSelector.append("$if$");
// ifSelector.append(Integer.toHexString(expr.toString().hashCode()));
// } else {
- // throw new BCException("Unexpected enclosing declaration of " + enclosingDec + " for if pointcut designator");
+ // throw new BCException("Unexpected enclosing declaration of " +
+ // enclosingDec + " for if pointcut designator");
// }
// hashcode of expression
ret.selector = ifSelector.toString().toCharArray();
ret.arguments = makeArguments(enclosingDec, containingTypeDec);
- ret.statements = new Statement[] { new ReturnStatement(expr, expr.sourceStart, expr.sourceEnd) };
+ ret.statements = new Statement[] { new ReturnStatement(expr,
+ expr.sourceStart, expr.sourceEnd) };
return ret;
}
- private Argument[] makeArguments(MethodDeclaration enclosingDec, TypeDeclaration containingTypeDec) {
+ private Argument[] makeArguments(MethodDeclaration enclosingDec,
+ TypeDeclaration containingTypeDec) {
Argument[] baseArguments = enclosingDec.arguments;
int len = baseArguments.length;
if (enclosingDec instanceof AdviceDeclaration) {
@@ -123,7 +185,8 @@ public class IfPseudoToken extends PseudoToken {
Argument[] ret = new Argument[len];
for (int i = 0; i < len; i++) {
Argument a = baseArguments[i];
- ret[i] = new Argument(a.name, AstUtil.makeLongPos(a.sourceStart, a.sourceEnd), a.type, Modifier.FINAL);
+ ret[i] = new Argument(a.name, AstUtil.makeLongPos(a.sourceStart,
+ a.sourceEnd), a.type, Modifier.FINAL);
}
ret = AdviceDeclaration.addTjpArguments(ret, containingTypeDec);
diff --git a/testing/newsrc/org/aspectj/testing/XMLBasedAjcTestCase.java b/testing/newsrc/org/aspectj/testing/XMLBasedAjcTestCase.java
index d4e46973d..9ecd5d885 100644
--- a/testing/newsrc/org/aspectj/testing/XMLBasedAjcTestCase.java
+++ b/testing/newsrc/org/aspectj/testing/XMLBasedAjcTestCase.java
@@ -31,6 +31,7 @@ import org.apache.commons.digester.Digester;
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.util.ClassPath;
import org.aspectj.apache.bcel.util.SyntheticRepository;
import org.aspectj.tools.ajc.AjcTestCase;
@@ -54,7 +55,7 @@ public abstract class XMLBasedAjcTestCase extends AjcTestCase {
public XMLBasedAjcTestCase() {
}
-
+
/**
* You must define a suite() method in subclasses, and return the result of calling this method. (Don't you hate static methods
* in programming models). For example:
@@ -317,6 +318,18 @@ public abstract class XMLBasedAjcTestCase extends AjcTestCase {
return repos.loadClass(clazzname);
}
+ protected Method getMethodStartsWith(JavaClass jc, String prefix) {
+ Method[] meths = jc.getMethods();
+ for (int i = 0; i < meths.length; i++) {
+ Method method = meths[i];
+ System.out.println(method);
+ if (method.getName().startsWith(prefix)) {
+ return method;
+ }
+ }
+ return null;
+ }
+
/**
* Sort it by name then start position
*/
diff --git a/tests/bugs172/pr398246/Code.java b/tests/bugs172/pr398246/Code.java
new file mode 100644
index 000000000..beacd74b4
--- /dev/null
+++ b/tests/bugs172/pr398246/Code.java
@@ -0,0 +1,19 @@
+import org.aspectj.lang.annotation.control.*;
+import java.lang.annotation.*;
+
+public class Code {
+ public static boolean isTrue = true;
+
+ public void m() {
+ }
+ public static void main(String []argv) {
+ new Code().m();
+ }
+}
+
+aspect X {
+ @CodeGenerationHint(ifNameSuffix="andy")
+ before(): execution(* Code.*(..)) && if(Code.isTrue) {
+ System.out.println("advice");
+ }
+}
diff --git a/tests/bugs172/pr398246/Code2.java b/tests/bugs172/pr398246/Code2.java
new file mode 100644
index 000000000..c8c0baafb
--- /dev/null
+++ b/tests/bugs172/pr398246/Code2.java
@@ -0,0 +1,20 @@
+import org.aspectj.lang.annotation.control.*;
+import java.lang.annotation.*;
+
+public class Code2 {
+ public static boolean isTrue = true;
+
+ public void m() {
+ }
+ public static void main(String []argv) {
+ new Code2().m();
+ }
+}
+
+aspect X {
+ @CodeGenerationHint(ifNameSuffix="fred")
+ pointcut p(): execution(* Code2.*(..)) && if(Code2.isTrue);
+ before(): p() {
+ System.out.println("advice");
+ }
+}
diff --git a/tests/bugs172/pr398246/Code3.java b/tests/bugs172/pr398246/Code3.java
new file mode 100644
index 000000000..5588905f1
--- /dev/null
+++ b/tests/bugs172/pr398246/Code3.java
@@ -0,0 +1,21 @@
+import java.lang.annotation.*;
+
+public class Code3 {
+ public static boolean isTrue = true;
+
+ public void m() {
+ }
+ public static void main(String []argv) {
+ new Code3().m();
+ }
+}
+
+aspect X {
+
+ @org.aspectj.lang.annotation.control.CodeGenerationHint(ifNameSuffix="barney")
+ pointcut p(): execution(* Code3.*(..)) && if(Code3.isTrue);
+
+ before(): p() {
+ System.out.println("advice");
+ }
+}
diff --git a/tests/bugs172/pr398246/Code4.java b/tests/bugs172/pr398246/Code4.java
new file mode 100644
index 000000000..488092d93
--- /dev/null
+++ b/tests/bugs172/pr398246/Code4.java
@@ -0,0 +1,21 @@
+import java.lang.annotation.*;
+
+public class Code4 {
+ public static boolean isTrue = true;
+
+ public void m() {
+ }
+ public static void main(String []argv) {
+ new Code4().m();
+ }
+}
+
+aspect X {
+
+ @org.aspectj.lang.annotation.control.CodeGenerationHint(ifNameSuffix="sid")
+ pointcut p(): execution(* Code*.*(..)) && if(Code4.isTrue);
+
+ before(): p() {
+ System.out.println("advice");
+ }
+}
diff --git a/tests/bugs172/pr398246/CodeExtra4.java b/tests/bugs172/pr398246/CodeExtra4.java
new file mode 100644
index 000000000..e192328d6
--- /dev/null
+++ b/tests/bugs172/pr398246/CodeExtra4.java
@@ -0,0 +1,11 @@
+import java.lang.annotation.*;
+
+public class CodeExtra4 {
+ public static boolean isTrue = true;
+
+ public void m() { }
+
+ public static void main(String []argv) {
+ new CodeExtra4().m();
+ }
+}
diff --git a/tests/src/org/aspectj/systemtest/ajc172/Ajc172Tests.java b/tests/src/org/aspectj/systemtest/ajc172/Ajc172Tests.java
index 292efcbee..eea4030d0 100644
--- a/tests/src/org/aspectj/systemtest/ajc172/Ajc172Tests.java
+++ b/tests/src/org/aspectj/systemtest/ajc172/Ajc172Tests.java
@@ -14,6 +14,8 @@ import java.io.File;
import junit.framework.Test;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.testing.XMLBasedAjcTestCase;
/**
@@ -21,6 +23,36 @@ import org.aspectj.testing.XMLBasedAjcTestCase;
*/
public class Ajc172Tests extends org.aspectj.testing.XMLBasedAjcTestCase {
+ public void testIfPointcutNames_pr398246() throws Exception{
+ runTest("if pointcut names");
+ JavaClass jc = getClassFrom(ajc.getSandboxDirectory(),"X");
+ Method m = getMethodStartsWith(jc,"ajc$if");
+ assertEquals("ajc$if$andy",m.getName());
+ }
+
+ public void testIfPointcutNames_pr398246_2() throws Exception {
+ runTest("if pointcut names 2");
+ JavaClass jc = getClassFrom(ajc.getSandboxDirectory(),"X");
+ Method m = getMethodStartsWith(jc,"ajc$if");
+ assertEquals("ajc$if$fred",m.getName());
+ }
+
+ // fully qualified annotation name is used
+ public void testIfPointcutNames_pr398246_3() throws Exception {
+ runTest("if pointcut names 3");
+ JavaClass jc = getClassFrom(ajc.getSandboxDirectory(),"X");
+ Method m = getMethodStartsWith(jc,"ajc$if");
+ assertEquals("ajc$if$barney",m.getName());
+ }
+
+ // compiling a class later than the initial build - does it pick up the right if clause name?
+ public void testIfPointcutNames_pr398246_4() throws Exception{
+ runTest("if pointcut names 4");
+ JavaClass jc = getClassFrom(ajc.getSandboxDirectory(),"X");
+ Method m = getMethodStartsWith(jc,"ajc$if");
+ assertEquals("ajc$if$sid",m.getName());
+ }
+
public void testOptionalAspects_pr398588() {
runTest("optional aspects");
}
diff --git a/tests/src/org/aspectj/systemtest/ajc172/ajc172.xml b/tests/src/org/aspectj/systemtest/ajc172/ajc172.xml
index 81217b60f..7dc6ce11b 100644
--- a/tests/src/org/aspectj/systemtest/ajc172/ajc172.xml
+++ b/tests/src/org/aspectj/systemtest/ajc172/ajc172.xml
@@ -33,6 +33,57 @@
</stdout>
</run>
</ajc-test>
+
+ <ajc-test dir="bugs172/pr398246" title="if pointcut names">
+ <compile files="Code.java" options="-1.5">
+ </compile>
+ <run class="Code" options="-1.5">
+ <stdout>
+ <line text="advice"/>
+ <line text="advice"/>
+ </stdout>
+ </run>
+ </ajc-test>
+
+ <ajc-test dir="bugs172/pr398246" title="if pointcut names 2">
+ <compile files="Code2.java" options="-1.5">
+ </compile>
+ <run class="Code2" options="-1.5">
+ <stdout>
+ <line text="advice"/>
+ <line text="advice"/>
+ </stdout>
+ </run>
+ </ajc-test>
+
+ <ajc-test dir="bugs172/pr398246" title="if pointcut names 3">
+ <compile files="Code3.java" options="-1.5">
+ </compile>
+ <run class="Code3" options="-1.5">
+ <stdout>
+ <line text="advice"/>
+ <line text="advice"/>
+ </stdout>
+ </run>
+ </ajc-test>
+
+ <ajc-test dir="bugs172/pr398246" title="if pointcut names 4">
+ <compile files="Code4.java" options="-1.5"></compile>
+ <compile files="Code4.java" options="-1.5" outjar="aspects.jar"/>
+ <run class="Code4" options="-1.5">
+ <stdout>
+ <line text="advice"/>
+ <line text="advice"/>
+ </stdout>
+ </run>
+ <compile files="CodeExtra4.java" aspectpath="aspects.jar" options="-1.5"></compile>
+ <run class="CodeExtra4" options="-1.5">
+ <stdout>
+ <line text="advice"/>
+ <line text="advice"/>
+ </stdout>
+ </run>
+ </ajc-test>
<ajc-test dir="bugs172/pr389750" title="inconsistent class file">
<compile files="Code.aj" options="-1.5">