aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/bugs/DisjunctVarBinding.java2
-rw-r--r--tests/bugs/DisjunctVarBinding_3.java2
-rw-r--r--tests/src/org/aspectj/systemtest/ajc120/ajc120-tests.xml3
-rw-r--r--tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml19
-rw-r--r--tests/src/org/aspectj/systemtest/ajc150/VarargsTests.java4
-rw-r--r--weaver/src/org/aspectj/weaver/Advice.java13
-rw-r--r--weaver/src/org/aspectj/weaver/Shadow.java13
-rw-r--r--weaver/src/org/aspectj/weaver/ShadowMunger.java5
-rw-r--r--weaver/src/org/aspectj/weaver/WeaverMessages.java5
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java254
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/AndPointcut.java21
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java18
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/AnnotationPatternList.java4
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java48
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java42
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java55
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java2
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java19
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java19
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java2
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java19
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/IfPointcut.java52
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java16
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java5
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/NotPointcut.java13
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java15
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/OrPointcut.java16
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java19
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/PerCflow.java9
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java11
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/PerObject.java20
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/PerSingleton.java11
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/Pointcut.java93
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java114
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/PointcutRewriter.java277
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java9
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java2
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java60
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java69
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java3
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/TypePattern.java36
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java3
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java48
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java58
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java13
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java27
-rw-r--r--weaver/src/org/aspectj/weaver/weaver-messages.properties6
-rw-r--r--weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java1
-rw-r--r--weaver/testsrc/org/aspectj/weaver/patterns/PointcutRewriterTest.java366
-rw-r--r--weaver/testsrc/org/aspectj/weaver/patterns/PointcutTestCase.java9
50 files changed, 1794 insertions, 156 deletions
diff --git a/tests/bugs/DisjunctVarBinding.java b/tests/bugs/DisjunctVarBinding.java
index 6d59f354f..7c40cd070 100644
--- a/tests/bugs/DisjunctVarBinding.java
+++ b/tests/bugs/DisjunctVarBinding.java
@@ -14,7 +14,7 @@ class B extends A {
aspect IfPointcut {
after(A a, B b) returning:
- call(* foo(*,*)) &&
+ execution(* foo(*,*)) &&
(args(b,a) || args(a,b)) {
System.out.println("Woven");
}
diff --git a/tests/bugs/DisjunctVarBinding_3.java b/tests/bugs/DisjunctVarBinding_3.java
index 3876b3521..95713d361 100644
--- a/tests/bugs/DisjunctVarBinding_3.java
+++ b/tests/bugs/DisjunctVarBinding_3.java
@@ -1,7 +1,7 @@
aspect IfPointcut {
after(A a, B b) returning:
- call(* foo(*,*)) &&
+ execution(* foo(*,*)) &&
(args(b,a) || args(a,b)) {
System.out.println("Woven");
}
diff --git a/tests/src/org/aspectj/systemtest/ajc120/ajc120-tests.xml b/tests/src/org/aspectj/systemtest/ajc120/ajc120-tests.xml
index 4ab8eb355..8381d4e01 100644
--- a/tests/src/org/aspectj/systemtest/ajc120/ajc120-tests.xml
+++ b/tests/src/org/aspectj/systemtest/ajc120/ajc120-tests.xml
@@ -454,8 +454,7 @@
<ajc-test dir="bugs"
pr="61568" title="wrong variable binding in || pointcuts">
<compile files="DisjunctVarBinding.java">
- <message kind="error" line="34" text="Ambiguous binding of type B"/>
- <message kind="error" line="34" text="Ambiguous binding of type A"/>
+ <message kind="error" line="17" text="ambiguous binding of parameter(s) a, b across '||' in pointcut"/>
</compile>
</ajc-test>
diff --git a/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml b/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml
index 77d52f3dc..9089289e9 100644
--- a/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml
+++ b/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml
@@ -4,12 +4,10 @@
<ajc-test dir="bugs"
pr="62073" title="false ambiguous binding error (introduced in 1.2rc2)">
<compile files="DisjunctVarBinding_2.java,DisjunctVarBinding_3.java">
- <message kind="error" line="25" file="DisjunctVarBinding_2.java" text="Ambiguous binding of type B"/>
- <message kind="error" line="25" file="DisjunctVarBinding_2.java" text="Ambiguous binding of type A"/>
+ <message kind="error" line="4" file="DisjunctVarBinding_3.java" text="ambiguous binding of parameter(s) a, b across '||' in pointcut"/>
</compile>
<compile files="DisjunctVarBinding_3.java,DisjunctVarBinding_2.java">
- <message kind="error" line="25" file="DisjunctVarBinding_2.java" text="Ambiguous binding of type B"/>
- <message kind="error" line="25" file="DisjunctVarBinding_2.java" text="Ambiguous binding of type A"/>
+ <message kind="error" line="4" file="DisjunctVarBinding_3.java" text="ambiguous binding of parameter(s) a, b across '||' in pointcut"/>
</compile>
</ajc-test>
@@ -213,14 +211,11 @@
<ajc-test dir="bugs/oxford" pr="65319"
title="ajc crashes when compiling the following program (binding this() and target())">
<compile files="PR65319.java">
- <message kind="error" line="7" text="Cannot use target() to match at this"/>
- <message kind="error" line="7" text="Cannot use this() to match at this"/>
- <message kind="error" line="11" text="Cannot use target() to match at this"/>
- <message kind="error" line="11" text="Cannot use this() to match at this"/>
- <message kind="error" line="11" text="Ambiguous binding of type Test"/>
- <message kind="error" line="15" text="Cannot use target() to match at this"/>
- <message kind="error" line="15" text="Cannot use this() to match at this"/>
- <message kind="error" line="15" text="Ambiguous binding of type Test"/>
+ <!-- target comes before this comes before args, and we only report one error -->
+ <message kind="error" line="23" text="ambiguous binding of parameter(s) x across '||' in pointcut"/>
+ <message kind="error" line="25" text="ambiguous binding of parameter(s) x across '||' in pointcut"/>
+ <message kind="error" line="27" text="ambiguous binding of parameter(s) x across '||' in pointcut"/>
+ <message kind="error" line="29" text="ambiguous binding of parameter(s) x across '||' in pointcut"/>
</compile>
</ajc-test>
diff --git a/tests/src/org/aspectj/systemtest/ajc150/VarargsTests.java b/tests/src/org/aspectj/systemtest/ajc150/VarargsTests.java
index 7845f6bd1..178e82b18 100644
--- a/tests/src/org/aspectj/systemtest/ajc150/VarargsTests.java
+++ b/tests/src/org/aspectj/systemtest/ajc150/VarargsTests.java
@@ -59,10 +59,12 @@ public class VarargsTests extends TestUtils {
// In this test, it can be tricky to understand the results!! The reason being that the shadow
// isn't included in the error message (it really should be, but thats a bit hard to do cleanly)
public void test003_cantMatchVarargsWithObjectArray_withincodePCD() {
- CompilationResult cR = binaryWeave("testcode.jar","VarargsAspect04.aj",0,7,true);
+ CompilationResult cR = binaryWeave("testcode.jar","VarargsAspect04.aj",0,6,true);
// There are 7. Each piece of the pointcut is matched against all the shadows, so both
// the 'withincode' PCD and the 'call' PCD are matched against every join point.
+ // AMC - there are now SIX. We detect early that a call(* *(..)) pcd cannot match
+ // constructor call shadows and never do the match.
assertTrue("Did not get expected message about a varargs mismatch, instead got: "+cR.getWarningMessages(),
((IMessage)cR.getWarningMessages().get(0)).toString().indexOf("varargs declared method")!=-1);
diff --git a/weaver/src/org/aspectj/weaver/Advice.java b/weaver/src/org/aspectj/weaver/Advice.java
index 9a6e57c10..bafbb3ef5 100644
--- a/weaver/src/org/aspectj/weaver/Advice.java
+++ b/weaver/src/org/aspectj/weaver/Advice.java
@@ -185,6 +185,17 @@ public abstract class Advice extends ShadowMunger {
return getSignature().getParameterTypes().length - getExtraParameterCount();
}
+ public String[] getBaseParameterNames(World world) {
+ String[] allNames = getSignature().getParameterNames(world);
+ int extras = getExtraParameterCount();
+ if (extras == 0) return allNames;
+ String[] result = new String[getBaseParameterCount()];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = allNames[i];
+ }
+ return result;
+ }
+
public TypeX getExtraParameterType() {
if (!hasExtraParameter()) return ResolvedTypeX.MISSING;
return signature.getParameterTypes()[getBaseParameterCount()];
@@ -215,7 +226,9 @@ public abstract class Advice extends ShadowMunger {
// assert !fromType.isAbstract();
Pointcut p = pointcut.concretize(fromType, signature.getArity(), this);
if (clause != null) {
+ Pointcut oldP = p;
p = new AndPointcut(clause, p);
+ p.copyLocationFrom(oldP);
p.state = Pointcut.CONCRETE;
}
diff --git a/weaver/src/org/aspectj/weaver/Shadow.java b/weaver/src/org/aspectj/weaver/Shadow.java
index 85cd0ad87..c7c3309a6 100644
--- a/weaver/src/org/aspectj/weaver/Shadow.java
+++ b/weaver/src/org/aspectj/weaver/Shadow.java
@@ -16,8 +16,10 @@ package org.aspectj.weaver;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.aspectj.asm.IRelationship;
import org.aspectj.bridge.*;
@@ -35,11 +37,16 @@ import org.aspectj.weaver.bcel.BcelAdvice;
*/
public abstract class Shadow {
+
+ // every Shadow has a unique id, doesn't matter if it wraps...
+ private static int nextShadowID = 100; // easier to spot than zero.
+
private final Kind kind;
private final Member signature;
protected final Shadow enclosingShadow;
protected List mungers = new ArrayList(1);
+ public int shadowId = nextShadowID++; // every time we build a shadow, it gets a new id
// ----
protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
@@ -202,6 +209,12 @@ public abstract class Shadow {
AdviceExecution, Initialization, ExceptionHandler,
};
+ public static final Set ALL_SHADOW_KINDS = new HashSet();
+ static {
+ for (int i = 0; i < SHADOW_KINDS.length; i++) {
+ ALL_SHADOW_KINDS.add(SHADOW_KINDS[i]);
+ }
+ }
/** A type-safe enum representing the kind of shadows
*/
diff --git a/weaver/src/org/aspectj/weaver/ShadowMunger.java b/weaver/src/org/aspectj/weaver/ShadowMunger.java
index 36218cdb2..9924d2e7f 100644
--- a/weaver/src/org/aspectj/weaver/ShadowMunger.java
+++ b/weaver/src/org/aspectj/weaver/ShadowMunger.java
@@ -106,6 +106,11 @@ public abstract class ShadowMunger implements PartialOrder.PartialComparable, IH
public Pointcut getPointcut() {
return pointcut;
}
+
+ // pointcut may be updated during rewriting...
+ public void setPointcut(Pointcut pointcut) {
+ this.pointcut = pointcut;
+ }
/**
diff --git a/weaver/src/org/aspectj/weaver/WeaverMessages.java b/weaver/src/org/aspectj/weaver/WeaverMessages.java
index 8aaa2e215..1fcde28ca 100644
--- a/weaver/src/org/aspectj/weaver/WeaverMessages.java
+++ b/weaver/src/org/aspectj/weaver/WeaverMessages.java
@@ -102,6 +102,11 @@ public class WeaverMessages {
public static final String XLINT_KEY_ERROR = "invalidXLintKey";
public static final String XLINT_VALUE_ERROR = "invalidXLintMessageKind";
+ public static final String UNBOUND_FORMAL = "unboundFormalInPC";
+ public static final String AMBIGUOUS_BINDING = "ambiguousBindingInPC";
+ public static final String AMBIGUOUS_BINDING_IN_OR = "ambiguousBindingInOrPC";
+ public static final String NEGATION_DOESNT_ALLOW_BINDING = "negationDoesntAllowBinding";
+
// Java5 messages
public static final String ITDC_ON_ENUM_NOT_ALLOWED = "itdcOnEnumNotAllowed";
public static final String ITDM_ON_ENUM_NOT_ALLOWED = "itdmOnEnumNotAllowed";
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java
index 1f850999e..fe6392bcb 100644
--- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java
@@ -27,9 +27,11 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
@@ -48,6 +50,7 @@ import org.aspectj.bridge.Message;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.util.FileUtil;
import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
import org.aspectj.weaver.ConcreteTypeMunger;
import org.aspectj.weaver.CrosscuttingMembersSet;
import org.aspectj.weaver.IClassFileProvider;
@@ -61,9 +64,19 @@ import org.aspectj.weaver.TypeX;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.WeaverMetrics;
import org.aspectj.weaver.WeaverStateInfo;
+import org.aspectj.weaver.patterns.AndPointcut;
+import org.aspectj.weaver.patterns.BindingAnnotationTypePattern;
+import org.aspectj.weaver.patterns.BindingTypePattern;
import org.aspectj.weaver.patterns.CflowPointcut;
+import org.aspectj.weaver.patterns.ConcreteCflowPointcut;
import org.aspectj.weaver.patterns.DeclareParents;
import org.aspectj.weaver.patterns.FastMatchInfo;
+import org.aspectj.weaver.patterns.IfPointcut;
+import org.aspectj.weaver.patterns.NameBindingPointcut;
+import org.aspectj.weaver.patterns.NotPointcut;
+import org.aspectj.weaver.patterns.OrPointcut;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.PointcutRewriter;
public class BcelWeaver implements IWeaver {
@@ -340,6 +353,7 @@ public class BcelWeaver implements IWeaver {
}
shadowMungerList = xcutSet.getShadowMungers();
+ rewritePointcuts(shadowMungerList);
typeMungerList = xcutSet.getTypeMungers();
declareParentsList = xcutSet.getDeclareParents();
@@ -353,6 +367,246 @@ public class BcelWeaver implements IWeaver {
});
}
+ /*
+ * Rewrite all of the pointcuts in the world into their most efficient
+ * form for subsequent matching. Also ensure that if pc1.equals(pc2)
+ * then pc1 == pc2 (for non-binding pcds) by making references all
+ * point to the same instance.
+ * Since pointcuts remember their match decision on the last shadow,
+ * this makes matching faster when many pointcuts share common elements,
+ * or even when one single pointcut has one common element (which can
+ * be a side-effect of DNF rewriting).
+ */
+ private void rewritePointcuts(List/*ShadowMunger*/ shadowMungers) {
+ PointcutRewriter rewriter = new PointcutRewriter();
+ for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) {
+ ShadowMunger munger = (ShadowMunger) iter.next();
+ Pointcut p = munger.getPointcut();
+ Pointcut newP = rewriter.rewrite(p);
+ // validateBindings now whilst we still have around the pointcut
+ // that resembles what the user actually wrote in their program
+ // text.
+ if (munger instanceof Advice) {
+ Advice advice = (Advice) munger;
+ if (advice.getSignature() != null) {
+ int numFormals = advice.getBaseParameterCount();
+ if (numFormals > 0) {
+ String[] names = advice.getBaseParameterNames(world);
+ validateBindings(newP,p,numFormals,names);
+ }
+ }
+ }
+ munger.setPointcut(newP);
+ }
+ // now that we have optimized individual pointcuts, optimize
+ // across the set of pointcuts....
+ // Use a map from key based on pc equality, to value based on
+ // pc identity.
+ Map/*<Pointcut,Pointcut>*/ pcMap = new HashMap();
+ for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) {
+ ShadowMunger munger = (ShadowMunger) iter.next();
+ Pointcut p = munger.getPointcut();
+ munger.setPointcut(shareEntriesFromMap(p,pcMap));
+ }
+ }
+
+ private Pointcut shareEntriesFromMap(Pointcut p,Map pcMap) {
+ // some things cant be shared...
+ if (p instanceof NameBindingPointcut) return p;
+ if (p instanceof IfPointcut) return p;
+ if (p instanceof ConcreteCflowPointcut) return p;
+ if (p instanceof AndPointcut) {
+ AndPointcut apc = (AndPointcut) p;
+ Pointcut left = shareEntriesFromMap(apc.getLeft(),pcMap);
+ Pointcut right = shareEntriesFromMap(apc.getRight(),pcMap);
+ return new AndPointcut(left,right);
+ } else if (p instanceof OrPointcut) {
+ OrPointcut opc = (OrPointcut) p;
+ Pointcut left = shareEntriesFromMap(opc.getLeft(),pcMap);
+ Pointcut right = shareEntriesFromMap(opc.getRight(),pcMap);
+ return new OrPointcut(left,right);
+ } else if (p instanceof NotPointcut) {
+ NotPointcut npc = (NotPointcut) p;
+ Pointcut not = shareEntriesFromMap(npc.getNegatedPointcut(),pcMap);
+ return new NotPointcut(not);
+ } else {
+ // primitive pcd
+ if (pcMap.containsKey(p)) { // based on equality
+ return (Pointcut) pcMap.get(p); // same instance (identity)
+ } else {
+ pcMap.put(p,p);
+ return p;
+ }
+ }
+ }
+
+ // userPointcut is the pointcut that the user wrote in the program text.
+ // dnfPointcut is the same pointcut rewritten in DNF
+ // numFormals is the number of formal parameters in the pointcut
+ // if numFormals > 0 then every branch of a disjunction must bind each formal once and only once.
+ // in addition, the left and right branches of a disjunction must hold on join point kinds in
+ // common.
+ private void validateBindings(Pointcut dnfPointcut, Pointcut userPointcut, int numFormals, String[] names) {
+ if (numFormals == 0) return; // nothing to check
+ if (dnfPointcut.couldMatchKinds().isEmpty()) return; // cant have problems if you dont match!
+ if (dnfPointcut instanceof OrPointcut) {
+ OrPointcut orBasedDNFPointcut = (OrPointcut) dnfPointcut;
+ Pointcut[] leftBindings = new Pointcut[numFormals];
+ Pointcut[] rightBindings = new Pointcut[numFormals];
+ validateOrBranch(orBasedDNFPointcut,userPointcut,numFormals,names,leftBindings,rightBindings);
+ } else {
+ Pointcut[] bindings = new Pointcut[numFormals];
+ validateSingleBranch(dnfPointcut, userPointcut, numFormals, names,bindings);
+ }
+ }
+
+ private void validateOrBranch(OrPointcut pc, Pointcut userPointcut, int numFormals,
+ String[] names, Pointcut[] leftBindings, Pointcut[] rightBindings) {
+ Pointcut left = pc.getLeft();
+ Pointcut right = pc.getRight();
+ if (left instanceof OrPointcut) {
+ Pointcut[] newRightBindings = new Pointcut[numFormals];
+ validateOrBranch((OrPointcut)left,userPointcut,numFormals,names,leftBindings,newRightBindings);
+ } else {
+ if (left.couldMatchKinds().size() > 0)
+ validateSingleBranch(left, userPointcut, numFormals, names, leftBindings);
+ }
+ if (right instanceof OrPointcut) {
+ Pointcut[] newLeftBindings = new Pointcut[numFormals];
+ validateOrBranch((OrPointcut)right,userPointcut,numFormals,names,newLeftBindings,rightBindings);
+ } else {
+ if (right.couldMatchKinds().size() > 0)
+ validateSingleBranch(right, userPointcut, numFormals, names, rightBindings);
+ }
+ Set kindsInCommon = left.couldMatchKinds();
+ kindsInCommon.retainAll(right.couldMatchKinds());
+ if (!kindsInCommon.isEmpty()) {
+ // we know that every branch binds every formal, so there is no ambiguity
+ // if each branch binds it in exactly the same way...
+ List ambiguousNames = new ArrayList();
+ for (int i = 0; i < numFormals; i++) {
+ if (!leftBindings[i].equals(rightBindings[i])) {
+ ambiguousNames.add(names[i]);
+ }
+ }
+ if (!ambiguousNames.isEmpty())
+ raiseAmbiguityInDisjunctionError(userPointcut,ambiguousNames);
+ }
+ }
+
+ // pc is a pointcut that does not contain any disjunctions
+ // check that every formal is bound (negation doesn't count).
+ // we know that numFormals > 0 or else we would not be called
+ private void validateSingleBranch(Pointcut pc, Pointcut userPointcut, int numFormals, String[] names, Pointcut[] bindings) {
+ boolean[] foundFormals = new boolean[numFormals];
+ for (int i = 0; i < foundFormals.length; i++) {
+ foundFormals[i] = false;
+ }
+ validateSingleBranchRecursion(pc, userPointcut, foundFormals, names, bindings);
+ for (int i = 0; i < foundFormals.length; i++) {
+ if (!foundFormals[i]) {
+ raiseUnboundFormalError(names[i],userPointcut);
+ }
+ }
+ }
+
+ // each formal must appear exactly once
+ private void validateSingleBranchRecursion(Pointcut pc, Pointcut userPointcut, boolean[] foundFormals, String[] names, Pointcut[] bindings) {
+ if (pc instanceof NotPointcut) {
+ // nots can only appear at leaves in DNF
+ NotPointcut not = (NotPointcut) pc;
+ if (not.getNegatedPointcut() instanceof NameBindingPointcut) {
+ NameBindingPointcut nnbp = (NameBindingPointcut) not.getNegatedPointcut();
+ if (!nnbp.getBindingAnnotationTypePatterns().isEmpty() && !nnbp.getBindingTypePatterns().isEmpty())
+ raiseNegationBindingError(userPointcut);
+ }
+ } else if (pc instanceof AndPointcut) {
+ AndPointcut and = (AndPointcut) pc;
+ validateSingleBranchRecursion(and.getLeft(), userPointcut,foundFormals,names,bindings);
+ validateSingleBranchRecursion(and.getRight(),userPointcut,foundFormals,names,bindings);
+ } else if (pc instanceof NameBindingPointcut) {
+ List/*BindingTypePattern*/ btps = ((NameBindingPointcut)pc).getBindingTypePatterns();
+ for (Iterator iter = btps.iterator(); iter.hasNext();) {
+ BindingTypePattern btp = (BindingTypePattern) iter.next();
+ int index = btp.getFormalIndex();
+ bindings[index] = pc;
+ if (foundFormals[index]) {
+ raiseAmbiguousBindingError(names[index],userPointcut);
+ } else {
+ foundFormals[index] = true;
+ }
+ }
+ List/*BindingAnnotationTypePattern*/ baps = ((NameBindingPointcut)pc).getBindingAnnotationTypePatterns();
+ for (Iterator iter = baps.iterator(); iter.hasNext();) {
+ BindingAnnotationTypePattern bap = (BindingAnnotationTypePattern) iter.next();
+ int index = bap.getFormalIndex();
+ bindings[index] = pc;
+ if (foundFormals[index]) {
+ raiseAmbiguousBindingError(names[index],userPointcut);
+ } else {
+ foundFormals[index] = true;
+ }
+ }
+ } else if (pc instanceof ConcreteCflowPointcut) {
+ ConcreteCflowPointcut cfp = (ConcreteCflowPointcut) pc;
+ int[] slots = cfp.getUsedFormalSlots();
+ for (int i = 0; i < slots.length; i++) {
+ bindings[slots[i]] = cfp;
+ if (foundFormals[slots[i]]) {
+ raiseAmbiguousBindingError(names[slots[i]],userPointcut);
+ } else {
+ foundFormals[slots[i]] = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param userPointcut
+ */
+ private void raiseNegationBindingError(Pointcut userPointcut) {
+ world.showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.NEGATION_DOESNT_ALLOW_BINDING),
+ userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
+ }
+
+ /**
+ * @param string
+ * @param userPointcut
+ */
+ private void raiseAmbiguousBindingError(String name, Pointcut userPointcut) {
+ world.showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING,
+ name),
+ userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
+ }
+
+ /**
+ * @param userPointcut
+ */
+ private void raiseAmbiguityInDisjunctionError(Pointcut userPointcut, List names) {
+ StringBuffer formalNames = new StringBuffer(names.get(0).toString());
+ for (int i = 1; i < names.size(); i++) {
+ formalNames.append(", ");
+ formalNames.append(names.get(i));
+ }
+ world.showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING_IN_OR,formalNames),
+ userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
+ }
+
+ /**
+ * @param string
+ * @param userPointcut
+ */
+ private void raiseUnboundFormalError(String name, Pointcut userPointcut) {
+ world.showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.UNBOUND_FORMAL,
+ name),
+ userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
+ }
+
+
// public void dumpUnwoven(File file) throws IOException {
// BufferedOutputStream os = FileUtil.makeOutputStream(file);
// this.zipOutputStream = new ZipOutputStream(os);
diff --git a/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java b/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java
index 812c5e0d5..1775ba3db 100644
--- a/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java
@@ -17,6 +17,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.HashSet;
+import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.util.FuzzyBoolean;
@@ -29,19 +31,28 @@ import org.aspectj.weaver.ast.Test;
public class AndPointcut extends Pointcut {
Pointcut left, right; // exposed for testing
+ private Set couldMatchKinds;
+
public AndPointcut(Pointcut left, Pointcut right) {
super();
this.left = left;
this.right = right;
this.pointcutKind = AND;
setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
+ couldMatchKinds = new HashSet();
+ couldMatchKinds.addAll(left.couldMatchKinds());
+ couldMatchKinds.retainAll(right.couldMatchKinds());
+ }
+
+ public Set couldMatchKinds() {
+ return couldMatchKinds;
}
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return left.fastMatch(type).and(right.fastMatch(type));
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return left.match(shadow).and(right.match(shadow));
}
@@ -114,13 +125,15 @@ public class AndPointcut extends Pointcut {
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return Test.makeAnd(left.findResidue(shadow, state), right.findResidue(shadow, state));
}
public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
- return new AndPointcut(left.concretize(inAspect, bindings),
- right.concretize(inAspect, bindings));
+ AndPointcut ret = new AndPointcut(left.concretize(inAspect, bindings),
+ right.concretize(inAspect, bindings));
+ ret.copyLocationFrom(this);
+ return ret;
}
public Pointcut getLeft() {
diff --git a/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java
index 15b705407..e3bb565b2 100644
--- a/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java
@@ -33,7 +33,7 @@ public class AndTypePattern extends TypePattern {
private TypePattern left, right;
public AndTypePattern(TypePattern left, TypePattern right) {
- super(false,false); //??? we override all methods that care about includeSubtypes
+ super(false,false); //?? we override all methods that care about includeSubtypes
this.left = left;
this.right = right;
setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
@@ -114,4 +114,20 @@ public class AndTypePattern extends TypePattern {
return buff.toString();
}
+ public boolean equals(Object obj) {
+ if (! (obj instanceof AndTypePattern)) return false;
+ AndTypePattern atp = (AndTypePattern) obj;
+ return left.equals(atp.left) && right.equals(atp.right);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ int ret = 17;
+ ret = ret + 37 * left.hashCode();
+ ret = ret + 37 * right.hashCode();
+ return ret;
+ }
+
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/AnnotationPatternList.java b/weaver/src/org/aspectj/weaver/patterns/AnnotationPatternList.java
index a5e8cc4cd..d586a824c 100644
--- a/weaver/src/org/aspectj/weaver/patterns/AnnotationPatternList.java
+++ b/weaver/src/org/aspectj/weaver/patterns/AnnotationPatternList.java
@@ -53,6 +53,10 @@ public class AnnotationPatternList extends PatternNode {
this((AnnotationTypePattern[]) l.toArray(new AnnotationTypePattern[l.size()]));
}
+ protected AnnotationTypePattern[] getAnnotationPatterns() {
+ return typePatterns;
+ }
+
public void resolve(World inWorld) {
for (int i = 0; i < typePatterns.length; i++) {
typePatterns[i].resolve(inWorld);
diff --git a/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java b/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java
index a2325e9d3..f156c7a7c 100644
--- a/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java
@@ -13,6 +13,10 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
@@ -67,6 +71,10 @@ public class AnnotationPointcut extends NameBindingPointcut {
this.munger = munger;
}
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
*/
@@ -81,7 +89,7 @@ public class AnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
*/
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
AnnotatedElement toMatchAgainst = null;
Member member = shadow.getSignature();
ResolvedMember rMember = member.resolve(shadow.getIWorld());
@@ -137,7 +145,7 @@ public class AnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
*/
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern)annotationTypePattern;
@@ -145,15 +153,15 @@ public class AnnotationPointcut extends NameBindingPointcut {
Var var = shadow.getKindedAnnotationVar(annotationType);
if (var == null) return Literal.FALSE;
// Check if we have already bound something to this formal
- if (state.get(btp.getFormalIndex())!=null) {
- ISourceLocation pcdSloc = getSourceLocation();
- ISourceLocation shadowSloc = shadow.getSourceLocation();
- Message errorMessage = new Message(
- "Cannot use @pointcut to match at this location and bind a formal to type '"+var.getType()+
- "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
- ". The secondary source location points to the problematic binding.",
- shadowSloc,true,new ISourceLocation[]{pcdSloc});
- shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
+ if ((state.get(btp.getFormalIndex())!=null) &&(lastMatchedShadowId == shadow.shadowId)) {
+// ISourceLocation pcdSloc = getSourceLocation();
+// ISourceLocation shadowSloc = shadow.getSourceLocation();
+// Message errorMessage = new Message(
+// "Cannot use @pointcut to match at this location and bind a formal to type '"+var.getType()+
+// "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
+// ". The secondary source location points to the problematic binding.",
+// shadowSloc,true,new ISourceLocation[]{pcdSloc});
+// shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
state.setErroneousVar(btp.getFormalIndex());
}
state.set(btp.getFormalIndex(),var);
@@ -162,6 +170,24 @@ public class AnnotationPointcut extends NameBindingPointcut {
}
/* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ public List getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ List l = new ArrayList();
+ l.add(annotationTypePattern);
+ return l;
+ } else return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ public List getBindingTypePatterns() {
+ return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
* @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
*/
public void write(DataOutputStream s) throws IOException {
diff --git a/weaver/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java
index 363e27928..d78dd8751 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java
@@ -12,6 +12,10 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
@@ -35,7 +39,7 @@ import org.aspectj.weaver.ast.Test;
public class ArgsAnnotationPointcut extends NameBindingPointcut {
private AnnotationPatternList arguments;
-
+
/**
*
*/
@@ -43,7 +47,11 @@ public class ArgsAnnotationPointcut extends NameBindingPointcut {
super();
this.arguments = arguments;
}
-
+
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS; // empty args() matches jps with no args
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
*/
@@ -54,7 +62,7 @@ public class ArgsAnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
*/
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
arguments.resolve(shadow.getIWorld());
FuzzyBoolean ret =
arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()));
@@ -91,13 +99,15 @@ public class ArgsAnnotationPointcut extends NameBindingPointcut {
return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
}
AnnotationPatternList list = arguments.resolveReferences(bindings);
- return new ArgsAnnotationPointcut(list);
+ Pointcut ret = new ArgsAnnotationPointcut(list);
+ ret.copyLocationFrom(this);
+ return ret;
}
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
*/
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
int len = shadow.getArgCount();
// do some quick length tests first
@@ -141,6 +151,28 @@ public class ArgsAnnotationPointcut extends NameBindingPointcut {
return ret;
}
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ public List getBindingAnnotationTypePatterns() {
+ List l = new ArrayList();
+ AnnotationTypePattern[] pats = arguments.getAnnotationPatterns();
+ for (int i = 0; i < pats.length; i++) {
+ if (pats[i] instanceof BindingAnnotationTypePattern) {
+ l.add(pats[i]);
+ }
+ }
+ return l;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ public List getBindingTypePatterns() {
+ return Collections.EMPTY_LIST;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
*/
diff --git a/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java
index 70f8535c7..aaa780cdd 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java
@@ -20,8 +20,12 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
@@ -53,12 +57,16 @@ public class ArgsPointcut extends NameBindingPointcut {
this.arguments = arguments;
this.pointcutKind = ARGS;
}
-
+
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS; // empty args() matches jps with no args
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
FuzzyBoolean ret =
arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()), TypePattern.DYNAMIC);
return ret;
@@ -135,6 +143,27 @@ public class ArgsPointcut extends NameBindingPointcut {
return ret;
}
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ public List getBindingAnnotationTypePatterns() {
+ return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ public List getBindingTypePatterns() {
+ List l = new ArrayList();
+ TypePattern[] pats = arguments.getTypePatterns();
+ for (int i = 0; i < pats.length; i++) {
+ if (pats[i] instanceof BindingTypePattern) {
+ l.add(pats[i]);
+ }
+ }
+ return l;
+ }
+
public void write(DataOutputStream s) throws IOException {
s.writeByte(Pointcut.ARGS);
arguments.write(s);
@@ -190,7 +219,9 @@ public class ArgsPointcut extends NameBindingPointcut {
if (inAspect.crosscuttingMembers != null) {
inAspect.crosscuttingMembers.exposeTypes(args.getExactTypes());
}
- return new ArgsPointcut(args);
+ Pointcut ret = new ArgsPointcut(args);
+ ret.copyLocationFrom(this);
+ return ret;
}
private Test findResidueNoEllipsis(Shadow shadow, ExposedState state, TypePattern[] patterns) {
@@ -218,14 +249,14 @@ public class ArgsPointcut extends NameBindingPointcut {
} else {
BindingTypePattern btp = (BindingTypePattern)type;
// Check if we have already bound something to this formal
- if (state.get(btp.getFormalIndex())!=null) {
- ISourceLocation isl = getSourceLocation();
- Message errorMessage = new Message(
- "Ambiguous binding of type "+type.getExactType().toString()+
- " using args(..) at this line - formal is already bound"+
- ". See secondary source location for location of args(..)",
- shadow.getSourceLocation(),true,new ISourceLocation[]{getSourceLocation()});
- shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
+ if ((state.get(btp.getFormalIndex())!=null) &&(lastMatchedShadowId != shadow.shadowId)) {
+// ISourceLocation isl = getSourceLocation();
+// Message errorMessage = new Message(
+// "Ambiguous binding of type "+type.getExactType().toString()+
+// " using args(..) at this line - formal is already bound"+
+// ". See secondary source location for location of args(..)",
+// shadow.getSourceLocation(),true,new ISourceLocation[]{getSourceLocation()});
+// shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
state.setErroneousVar(btp.getFormalIndex());
}
}
@@ -236,7 +267,7 @@ public class ArgsPointcut extends NameBindingPointcut {
return ret;
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
if (arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()), TypePattern.DYNAMIC).alwaysFalse()) {
return Literal.FALSE;
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java
index e2633aa3f..b49b75f8b 100644
--- a/weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java
@@ -40,6 +40,8 @@ public class BindingTypePattern extends ExactTypePattern implements BindingPatte
public boolean equals(Object other) {
if (!(other instanceof BindingTypePattern)) return false;
BindingTypePattern o = (BindingTypePattern)other;
+ if (includeSubtypes != o.includeSubtypes) return false;
+ if (isVarArgs != o.isVarArgs) return false;
return o.type.equals(this.type) && o.formalIndex == this.formalIndex;
}
public int hashCode() {
diff --git a/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java
index 5a94ec668..7203339f8 100644
--- a/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.util.FileUtil;
@@ -66,12 +67,16 @@ public class CflowPointcut extends Pointcut {
this.freeVars = freeVars;
this.pointcutKind = CFLOW;
}
-
+
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
//??? this is not maximally efficient
return FuzzyBoolean.MAYBE;
}
@@ -147,7 +152,7 @@ public class CflowPointcut extends Pointcut {
return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")";
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
throw new RuntimeException("unimplemented");
}
@@ -227,7 +232,9 @@ public class CflowPointcut extends Pointcut {
putCflowfield(concreteEntry,localCflowField); // Remember it
}
- return new ConcreteCflowPointcut(localCflowField, null,true);
+ Pointcut ret = new ConcreteCflowPointcut(localCflowField, null,true);
+ ret.copyLocationFrom(this);
+ return ret;
} else {
List slots = new ArrayList();
@@ -268,7 +275,9 @@ public class CflowPointcut extends Pointcut {
world.makeCflowStackFieldAdder(localCflowField));
putCflowfield(concreteEntry,localCflowField);
}
- return new ConcreteCflowPointcut(localCflowField, slots,false);
+ Pointcut ret = new ConcreteCflowPointcut(localCflowField, slots,false);
+ ret.copyLocationFrom(this);
+ return ret;
}
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
index a536dd4fa..9c1309c74 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
@@ -17,6 +17,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.IntMap;
@@ -43,11 +44,15 @@ public class ConcreteCflowPointcut extends Pointcut {
this.pointcutKind = CFLOW;
}
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
//??? this is not maximally efficient
return FuzzyBoolean.MAYBE;
}
@@ -70,6 +75,16 @@ public class ConcreteCflowPointcut extends Pointcut {
throw new UnsupportedOperationException("cflow pointcut matching not supported by this operation");
}
+ // used by weaver when validating bindings
+ public int[] getUsedFormalSlots() {
+ if (slots == null) return new int[0];
+ int[] indices = new int[slots.size()];
+ for (int i = 0; i < indices.length; i++) {
+ indices[i] = ((Slot)slots.get(i)).formalIndex;
+ }
+ return indices;
+ }
+
public void write(DataOutputStream s) throws IOException {
throw new RuntimeException("unimplemented");
}
@@ -97,7 +112,7 @@ public class ConcreteCflowPointcut extends Pointcut {
return "concretecflow(" + cflowField + ")";
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
//System.out.println("find residue: " + this);
if (usesCounter) {
return Test.makeFieldGetCall(cflowField, cflowCounterIsValidMethod, Expr.NONE);
diff --git a/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java
index 945b76ba7..4b2ca0c36 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java
@@ -151,6 +151,8 @@ public class ExactTypePattern extends TypePattern {
public boolean equals(Object other) {
if (!(other instanceof ExactTypePattern)) return false;
ExactTypePattern o = (ExactTypePattern)other;
+ if (includeSubtypes != o.includeSubtypes) return false;
+ if (isVarArgs != o.isVarArgs) return false;
return (o.type.equals(this.type) && o.annotationPattern.equals(this.annotationPattern));
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java b/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java
index ce6163055..f27f1f81d 100644
--- a/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java
@@ -17,6 +17,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.HashSet;
+import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.util.FuzzyBoolean;
@@ -37,17 +39,26 @@ import org.aspectj.weaver.internal.tools.PointcutExpressionImpl;
public class HandlerPointcut extends Pointcut {
TypePattern exceptionType;
+ private static final Set MATCH_KINDS = new HashSet();
+ static {
+ MATCH_KINDS.add(Shadow.ExceptionHandler);
+ }
+
public HandlerPointcut(TypePattern exceptionType) {
this.exceptionType = exceptionType;
this.pointcutKind = HANDLER;
}
+ public Set couldMatchKinds() {
+ return MATCH_KINDS;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
//??? should be able to do better by finding all referenced types in type
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
if (shadow.getKind() != Shadow.ExceptionHandler) return FuzzyBoolean.NO;
// we know we have exactly one parameter since we're checking an exception handler
@@ -134,11 +145,13 @@ public class HandlerPointcut extends Pointcut {
exceptionType = exceptionType.resolveBindingsFromRTTI(false,false);
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
}
public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
- return new HandlerPointcut(exceptionType);
+ Pointcut ret = new HandlerPointcut(exceptionType);
+ ret.copyLocationFrom(this);
+ return ret;
}
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java b/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java
index 1336adb2f..612d18a01 100644
--- a/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java
@@ -18,7 +18,9 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.lang.JoinPoint;
@@ -54,15 +56,27 @@ public class IfPointcut extends Pointcut {
this.pointcutKind = IF;
}
- public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
//??? this is not maximally efficient
return FuzzyBoolean.MAYBE;
}
+ public boolean alwaysFalse() {
+ return false;
+ }
+
+ public boolean alwaysTrue() {
+ return false;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#matchesDynamically(java.lang.Object, java.lang.Object, java.lang.Object[])
*/
@@ -116,7 +130,7 @@ public class IfPointcut extends Pointcut {
//??? The implementation of name binding and type checking in if PCDs is very convoluted
// There has to be a better way...
private boolean findingResidue = false;
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
if (findingResidue) return Literal.TRUE;
findingResidue = true;
try {
@@ -161,9 +175,16 @@ public class IfPointcut extends Pointcut {
}
}
+
+ // amc - the only reason this override seems to be here is to stop the copy, but
+ // that can be prevented by overriding shouldCopyLocationForConcretization,
+ // allowing me to make the method final in Pointcut.
+// public Pointcut concretize(ResolvedTypeX inAspect, IntMap bindings) {
+// return this.concretize1(inAspect, bindings);
+// }
- public Pointcut concretize(ResolvedTypeX inAspect, IntMap bindings) {
- return this.concretize1(inAspect, bindings);
+ protected boolean shouldCopyLocationForConcretize() {
+ return false;
}
private IfPointcut partiallyConcretized = null;
@@ -183,6 +204,7 @@ public class IfPointcut extends Pointcut {
return partiallyConcretized;
}
IfPointcut ret = new IfPointcut(testMethod, extraParameterFlags);
+ ret.copyLocationFrom(this);
partiallyConcretized = ret;
// It is possible to directly code your pointcut expression in a per clause
@@ -239,7 +261,15 @@ public class IfPointcut extends Pointcut {
super(null,0);
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ public Set couldMatchKinds() {
+ return Collections.EMPTY_SET;
+ }
+
+ public boolean alwaysFalse() {
+ return true;
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return Literal.FALSE; // can only get here if an earlier error occurred
}
@@ -247,7 +277,7 @@ public class IfPointcut extends Pointcut {
return FuzzyBoolean.NO;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return FuzzyBoolean.NO;
}
@@ -304,8 +334,12 @@ public class IfPointcut extends Pointcut {
public IfTruePointcut() {
super(null,0);
}
+
+ public boolean alwaysTrue() {
+ return true;
+ }
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return Literal.TRUE; // can only get here if an earlier error occurred
}
@@ -313,7 +347,7 @@ public class IfPointcut extends Pointcut {
return FuzzyBoolean.YES;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return FuzzyBoolean.YES;
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java
index 1e34b1404..8886e3209 100644
--- a/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java
@@ -16,6 +16,8 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.lang.JoinPoint;
@@ -36,6 +38,7 @@ import org.aspectj.weaver.ast.Test;
public class KindedPointcut extends Pointcut {
Shadow.Kind kind;
SignaturePattern signature;
+ private Set matchKinds;
private ShadowMunger munger = null; // only set after concretization
@@ -45,6 +48,8 @@ public class KindedPointcut extends Pointcut {
this.kind = kind;
this.signature = signature;
this.pointcutKind = KINDED;
+ this.matchKinds = new HashSet();
+ matchKinds.add(kind);
}
public KindedPointcut(
Shadow.Kind kind,
@@ -54,6 +59,13 @@ public class KindedPointcut extends Pointcut {
this(kind, signature);
this.munger = munger;
}
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.Pointcut#couldMatchKinds()
+ */
+ public Set couldMatchKinds() {
+ return matchKinds;
+ }
public FuzzyBoolean fastMatch(FastMatchInfo info) {
if (info.getKind() != null) {
@@ -63,7 +75,7 @@ public class KindedPointcut extends Pointcut {
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
if (shadow.getKind() != kind) return FuzzyBoolean.NO;
if (!signature.matches(shadow.getSignature(), shadow.getIWorld())){
@@ -265,7 +277,7 @@ public class KindedPointcut extends Pointcut {
signature = signature.resolveBindingsFromRTTI();
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java b/weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java
index 6fa9af440..b6be31406 100644
--- a/weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java
@@ -13,6 +13,8 @@
package org.aspectj.weaver.patterns;
+import java.util.List;
+
import org.aspectj.weaver.TypeX;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Test;
@@ -40,7 +42,8 @@ public abstract class NameBindingPointcut extends Pointcut {
return Test.makeInstanceof(var, myType.resolve(world));
}
-
+ public abstract List/*<BindingTypePattern>*/ getBindingTypePatterns();
+ public abstract List/*<BindingAnnotationTypePattern>*/ getBindingAnnotationTypePatterns();
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java b/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java
index 688f2e9c0..ea2587ed5 100644
--- a/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java
@@ -17,6 +17,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.util.FuzzyBoolean;
@@ -39,13 +40,17 @@ public class NotPointcut extends Pointcut {
setLocation(pointcut.getSourceContext(), startPos, pointcut.getEnd());
}
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
public Pointcut getNegatedPointcut() { return body; }
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return body.fastMatch(type).not();
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return body.match(shadow).not();
}
@@ -118,12 +123,14 @@ public class NotPointcut extends Pointcut {
return ret;
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return Test.makeNot(body.findResidue(shadow, state));
}
public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
- return new NotPointcut(body.concretize(inAspect, bindings));
+ Pointcut ret = new NotPointcut(body.concretize(inAspect, bindings));
+ ret.copyLocationFrom(this);
+ return ret;
}
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java
index cbe48e03b..8a0d2c619 100644
--- a/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java
@@ -105,4 +105,19 @@ public class NotTypePattern extends TypePattern {
}
return buff.toString();
}
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (! (obj instanceof NotTypePattern)) return false;
+ return (pattern.equals(((NotTypePattern)obj).pattern));
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return 17 + 37 * pattern.hashCode();
+ }
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java b/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java
index fa9efda07..e204ef329 100644
--- a/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java
@@ -17,6 +17,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.HashSet;
+import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.util.FuzzyBoolean;
@@ -28,6 +30,7 @@ import org.aspectj.weaver.ast.Test;
public class OrPointcut extends Pointcut {
private Pointcut left, right;
+ private Set couldMatchKinds;
public OrPointcut(Pointcut left, Pointcut right) {
super();
@@ -35,14 +38,19 @@ public class OrPointcut extends Pointcut {
this.right = right;
setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
this.pointcutKind = OR;
+ this.couldMatchKinds = new HashSet(left.couldMatchKinds());
+ this.couldMatchKinds.addAll(right.couldMatchKinds());
}
+ public Set couldMatchKinds() {
+ return couldMatchKinds;
+ }
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return left.fastMatch(type).or(right.fastMatch(type));
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return left.match(shadow).or(right.match(shadow));
}
@@ -119,13 +127,15 @@ public class OrPointcut extends Pointcut {
return ret;
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return Test.makeOr(left.findResidue(shadow, state), right.findResidue(shadow, state));
}
public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
- return new OrPointcut(left.concretize(inAspect, bindings),
+ Pointcut ret = new OrPointcut(left.concretize(inAspect, bindings),
right.concretize(inAspect, bindings));
+ ret.copyLocationFrom(this);
+ return ret;
}
public Pointcut getLeft() {
diff --git a/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java
index 37fa7767a..d071c942d 100644
--- a/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java
@@ -113,4 +113,23 @@ public class OrTypePattern extends TypePattern {
}
return buff.toString();
}
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (! (obj instanceof OrTypePattern)) return false;
+ OrTypePattern other = (OrTypePattern) obj;
+ return left.equals(other.left) && right.equals(other.right);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ int ret = 17;
+ ret = ret + 37 * left.hashCode();
+ ret = ret + 37 * right.hashCode();
+ return ret;
+ }
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java
index f0626758f..d03daa5eb 100644
--- a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java
+++ b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java
@@ -20,6 +20,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.Advice;
@@ -47,11 +48,15 @@ public class PerCflow extends PerClause {
// -----
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return FuzzyBoolean.YES;
}
@@ -60,7 +65,7 @@ public class PerCflow extends PerClause {
entry.resolve(scope);
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
Expr myInstance =
Expr.makeCallExpr(AjcMemberMaker.perCflowAspectOfMethod(inAspect),
Expr.NONE, inAspect);
diff --git a/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java b/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java
index 5b6acce03..c7274ea81 100644
--- a/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java
+++ b/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java
@@ -16,6 +16,7 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.Set;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.util.FuzzyBoolean;
@@ -31,12 +32,16 @@ public class PerFromSuper extends PerClause {
public PerFromSuper(PerClause.Kind kind) {
this.kind = kind;
}
-
+
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
throw new RuntimeException("unimplemented");
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
throw new RuntimeException("unimplemented");
}
@@ -44,7 +49,7 @@ public class PerFromSuper extends PerClause {
// this method intentionally left blank
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
throw new RuntimeException("unimplemented");
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/PerObject.java b/weaver/src/org/aspectj/weaver/patterns/PerObject.java
index bed5d4e81..ef74a8d13 100644
--- a/weaver/src/org/aspectj/weaver/patterns/PerObject.java
+++ b/weaver/src/org/aspectj/weaver/patterns/PerObject.java
@@ -16,6 +16,9 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.Advice;
@@ -33,11 +36,24 @@ import org.aspectj.weaver.ast.Var;
public class PerObject extends PerClause {
private boolean isThis;
private Pointcut entry;
+ private static final Set thisKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+ private static final Set targetKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+ static {
+ for (Iterator iter = Shadow.ALL_SHADOW_KINDS.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ if (kind.neverHasThis()) thisKindSet.remove(kind);
+ if (kind.neverHasTarget()) targetKindSet.remove(kind);
+ }
+ }
public PerObject(Pointcut entry, boolean isThis) {
this.entry = entry;
this.isThis = isThis;
}
+
+ public Set couldMatchKinds() {
+ return isThis ? thisKindSet : targetKindSet;
+ }
// -----
public FuzzyBoolean fastMatch(FastMatchInfo type) {
@@ -45,7 +61,7 @@ public class PerObject extends PerClause {
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
//System.err.println("matches " + this + " ? " + shadow + ", " + shadow.hasTarget());
//??? could probably optimize this better by testing could match
if (isThis) return FuzzyBoolean.fromBoolean(shadow.hasThis());
@@ -61,7 +77,7 @@ public class PerObject extends PerClause {
return isThis ? shadow.getThisVar() : shadow.getTargetVar();
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
Expr myInstance =
Expr.makeCallExpr(AjcMemberMaker.perObjectAspectOfMethod(inAspect),
new Expr[] {getVar(shadow)}, inAspect);
diff --git a/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java
index 2ffeec761..f4d8b9879 100644
--- a/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java
+++ b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java
@@ -16,6 +16,7 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.Set;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.AjcMemberMaker;
@@ -29,12 +30,16 @@ import org.aspectj.weaver.ast.Test;
public class PerSingleton extends PerClause {
public PerSingleton() {
}
-
+
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.YES;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return FuzzyBoolean.YES;
}
@@ -42,7 +47,7 @@ public class PerSingleton extends PerClause {
// this method intentionally left blank
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
Expr myInstance =
Expr.makeCallExpr(AjcMemberMaker.perSingletonAspectOfMethod(inAspect),
Expr.NONE, inAspect);
diff --git a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java
index 0cc96ef3d..1ba966c05 100644
--- a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java
@@ -17,6 +17,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.Collections;
+import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.util.FuzzyBoolean;
@@ -40,6 +42,43 @@ import org.aspectj.weaver.ast.Test;
*
* @author Erik Hilsdale
* @author Jim Hugunin
+ *
+ * A day in the life of a pointcut.... - AMC.
+ * ==========================================
+ *
+ * Pointcuts are created by the PatternParser, which is called by ajdt to
+ * parse a pointcut from the PseudoTokens AST node (which in turn are part
+ * of a PointcutDesignator AST node).
+ *
+ * Pointcuts are resolved by ajdt when an AdviceDeclaration or a
+ * PointcutDeclaration has its statements resolved. This happens as
+ * part of completeTypeBindings in the AjLookupEnvironment which is
+ * called after the diet parse phase of the compiler. Named pointcuts,
+ * and references to named pointcuts are instances of ReferencePointcut.
+ *
+ * At the end of the compilation process, the pointcuts are serialized
+ * (write method) into attributes in the class file.
+ *
+ * When the weaver loads the class files, it unpacks the attributes
+ * and deserializes the pointcuts (read). All aspects are added to the
+ * world, by calling addOrReplaceAspect on
+ * the crosscutting members set of the world. When aspects are added or
+ * replaced, the crosscutting members in the aspect are extracted as
+ * ShadowMungers (each holding a pointcut). The ShadowMungers are
+ * concretized, which concretizes the pointcuts. At this stage
+ * ReferencePointcuts are replaced by their declared content.
+ *
+ * During weaving, the weaver processes type by type. It first culls
+ * potentially matching ShadowMungers by calling the fastMatch method
+ * on their pointcuts. Only those that might match make it through to
+ * the next phase. At the next phase, all of the shadows within the
+ * type are created and passed to the pointcut for matching (match).
+ *
+ * When the actual munging happens, matched pointcuts are asked for
+ * their residue (findResidue) - the runtime test if any. Because of
+ * negation, findResidue may be called on pointcuts that could never
+ * match the shadow.
+ *
*/
public abstract class Pointcut extends PatternNode implements PointcutExpressionMatching {
public static final class State extends TypeSafeEnum {
@@ -53,9 +92,13 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression
public static final State CONCRETE = new State("concrete", 2);
protected byte pointcutKind;
-
+
public State state;
+ protected int lastMatchedShadowId;
+ private FuzzyBoolean lastMatchedShadowResult;
+ private Test lastMatchedShadowResidue;
+
/**
* Constructor for Pattern.
*/
@@ -69,12 +112,31 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression
* Could I match any shadows in the code defined within this type?
*/
public abstract FuzzyBoolean fastMatch(FastMatchInfo info);
+
+ /**
+ * The set of ShadowKinds that this Pointcut could possibly match
+ */
+ public abstract /*Enum*/Set/*<Shadow.Kind>*/ couldMatchKinds();
/**
* Do I really match this shadow?
* XXX implementors need to handle state
*/
- public abstract FuzzyBoolean match(Shadow shadow);
+ public final FuzzyBoolean match(Shadow shadow) {
+ if (shadow.shadowId == lastMatchedShadowId) return lastMatchedShadowResult;
+ FuzzyBoolean ret;
+ // this next test will prevent a lot of un-needed matching going on....
+ if (couldMatchKinds().contains(shadow.getKind())) {
+ ret = matchInternal(shadow);
+ } else {
+ ret = FuzzyBoolean.NO;
+ }
+ lastMatchedShadowId = shadow.shadowId;
+ lastMatchedShadowResult = ret;
+ return ret;
+ }
+
+ protected abstract FuzzyBoolean matchInternal(Shadow shadow);
/*
* for runtime / dynamic pointcuts.
@@ -143,7 +205,7 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression
/**
* Returns this pointcut mutated
*/
- public Pointcut resolve(IScope scope) {
+ public final Pointcut resolve(IScope scope) {
assertState(SYMBOLIC);
Bindings bindingTable = new Bindings(scope.getFormalCount());
this.resolveBindings(scope, bindingTable);
@@ -164,14 +226,15 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression
/**
* Returns a new pointcut
+ * Only used by test cases
*/
- public Pointcut concretize(ResolvedTypeX inAspect, int arity) {
+ public final Pointcut concretize(ResolvedTypeX inAspect, int arity) {
return concretize(inAspect, IntMap.idMap(arity));
}
//XXX this is the signature we're moving to
- public Pointcut concretize(ResolvedTypeX inAspect, int arity, ShadowMunger advice) {
+ public final Pointcut concretize(ResolvedTypeX inAspect, int arity, ShadowMunger advice) {
//if (state == CONCRETE) return this; //???
IntMap map = IntMap.idMap(arity);
map.setEnclosingAdvice(advice);
@@ -187,7 +250,7 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression
}
- public Pointcut concretize(ResolvedTypeX inAspect, IntMap bindings) {
+ public final Pointcut concretize(ResolvedTypeX inAspect, IntMap bindings) {
//!!! add this test -- assertState(RESOLVED);
Pointcut ret = this.concretize1(inAspect, bindings);
if (shouldCopyLocationForConcretize()) ret.copyLocationFrom(this);
@@ -221,7 +284,15 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression
* This can be called from NotPointcut even for Pointcuts that
* don't match the shadow
*/
- public abstract Test findResidue(Shadow shadow, ExposedState state);
+ public final Test findResidue(Shadow shadow, ExposedState state) {
+// if (shadow.shadowId == lastMatchedShadowId) return lastMatchedShadowResidue;
+ Test ret = findResidueInternal(shadow,state);
+// lastMatchedShadowResidue = ret;
+ lastMatchedShadowId = shadow.shadowId;
+ return ret;
+ }
+
+ protected abstract Test findResidueInternal(Shadow shadow,ExposedState state);
//XXX we're not sure whether or not this is needed
//XXX currently it's unused we're keeping it around as a stub
@@ -272,15 +343,19 @@ public abstract class Pointcut extends PatternNode implements PointcutExpression
}
private static class MatchesNothingPointcut extends Pointcut {
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return Literal.FALSE; // can only get here if an earlier error occurred
}
+ public Set couldMatchKinds() {
+ return Collections.EMPTY_SET;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.NO;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return FuzzyBoolean.NO;
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java b/weaver/src/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java
new file mode 100644
index 000000000..578670031
--- /dev/null
+++ b/weaver/src/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java
@@ -0,0 +1,114 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * 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
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.util.Comparator;
+
+import org.aspectj.weaver.Shadow;
+
+public class PointcutEvaluationExpenseComparator implements Comparator {
+
+ private static final int MATCHES_NOTHING = -1;
+ private static final int WITHIN = 1;
+ private static final int ATWITHIN = 2;
+ private static final int STATICINIT = 3;
+ private static final int ADVICEEXECUTION = 4;
+ private static final int HANDLER = 5;
+ private static final int GET_OR_SET = 6;
+ private static final int WITHINCODE = 7;
+ private static final int ATWITHINCODE = 8;
+ private static final int EXE_INIT_PREINIT = 9;
+ private static final int CALL = 10;
+ private static final int ANNOTATION = 11;
+ private static final int THIS_OR_TARGET = 12;
+ private static final int AT_THIS_OR_TARGET = 13;
+ private static final int ARGS = 14;
+ private static final int AT_ARGS = 15;
+ private static final int CFLOW = 16;
+ private static final int IF = 17;
+ private static final int OTHER = 20;
+
+ /**
+ * Compare 2 pointcuts based on an estimate of how expensive they may be
+ * to evaluate.
+ *
+ * within
+ * @within
+ * staticinitialization [make sure this has a fast match method]
+ * adviceexecution
+ * handler
+ * get, set
+ * withincode
+ * @withincode
+ * execution, initialization, preinitialization
+ * call
+ * @annotation
+ * this, target
+ * @this, @target
+ * args
+ * @args
+ * cflow, cflowbelow
+ * if
+ */
+ public int compare(Object o1, Object o2) {
+ Pointcut p1 = (Pointcut) o1;
+ Pointcut p2 = (Pointcut) o2;
+
+ // important property for a well-defined comparator
+ if (p1.equals(p2)) return 0;
+ int result = getScore(p1) - getScore(p2);
+ if (result == 0) {
+ // they have the same evaluation expense, but are not 'equal'
+ // sort by hashCode
+ result = p1.hashCode() - p2.hashCode();
+ if (result == 0) /*not allowed if ne*/ return -1;
+ }
+ return result;
+ }
+
+ // a higher score means a more expensive evaluation
+ private int getScore(Pointcut p) {
+ if (p.couldMatchKinds().isEmpty()) return MATCHES_NOTHING;
+ if (p instanceof WithinPointcut) return WITHIN;
+ if (p instanceof WithinAnnotationPointcut) return ATWITHIN;
+ if (p instanceof KindedPointcut) {
+ KindedPointcut kp = (KindedPointcut) p;
+ Shadow.Kind kind = kp.getKind();
+ if (kind == Shadow.AdviceExecution) {
+ return ADVICEEXECUTION;
+ } else if ((kind == Shadow.ConstructorCall) || (kind == Shadow.MethodCall)) {
+ return CALL;
+ } else if ((kind == Shadow.ConstructorExecution) || (kind == Shadow.MethodExecution) ||
+ (kind == Shadow.Initialization) || (kind == Shadow.PreInitialization)) {
+ return EXE_INIT_PREINIT;
+ } else if (kind == Shadow.ExceptionHandler) {
+ return HANDLER;
+ } else if ((kind == Shadow.FieldGet) || (kind == Shadow.FieldSet)) {
+ return GET_OR_SET;
+ } else if (kind == Shadow.StaticInitialization) {
+ return STATICINIT;
+ } else return OTHER;
+ }
+ if (p instanceof AnnotationPointcut) return ANNOTATION;
+ if (p instanceof ArgsPointcut) return ARGS;
+ if (p instanceof ArgsAnnotationPointcut) return AT_ARGS;
+ if (p instanceof CflowPointcut) return CFLOW;
+ if (p instanceof HandlerPointcut) return HANDLER;
+ if (p instanceof IfPointcut) return IF;
+ if (p instanceof ThisOrTargetPointcut) return THIS_OR_TARGET;
+ if (p instanceof ThisOrTargetAnnotationPointcut) return AT_THIS_OR_TARGET;
+ if (p instanceof WithincodePointcut) return WITHINCODE;
+ if (p instanceof WithinCodeAnnotationPointcut) return ATWITHINCODE;
+ if (p instanceof NotPointcut) return getScore(((NotPointcut)p).getNegatedPointcut());
+ if (p instanceof AndPointcut) return getScore(((AndPointcut)p).getLeft());
+ if (p instanceof OrPointcut) return getScore(((OrPointcut)p).getLeft());
+ return OTHER;
+ }
+}
diff --git a/weaver/src/org/aspectj/weaver/patterns/PointcutRewriter.java b/weaver/src/org/aspectj/weaver/patterns/PointcutRewriter.java
new file mode 100644
index 000000000..8b725721b
--- /dev/null
+++ b/weaver/src/org/aspectj/weaver/patterns/PointcutRewriter.java
@@ -0,0 +1,277 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * 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
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.aspectj.weaver.Shadow;
+
+/**
+ * @author colyer
+ *
+ * Performs term rewriting for pointcut expressions.
+ *
+ */
+public class PointcutRewriter {
+
+ private static final boolean WATCH_PROGRESS = false;
+
+ public Pointcut rewrite(Pointcut pc) {
+ if (WATCH_PROGRESS) System.out.println(pc);
+ Pointcut result = distributeNot(pc);
+ if (WATCH_PROGRESS) System.out.println("==> " + result);
+ result = pullUpDisjunctions(result);
+ if (WATCH_PROGRESS) System.out.println("==> " + result);
+ result = simplifyAnds(result);
+ if (WATCH_PROGRESS) System.out.println("==> " + result);
+ result = sortOrs(result);
+ if (WATCH_PROGRESS) System.out.println("==> " + result);
+ return result;
+ }
+
+
+ // !!X => X
+ // !(X && Y) => !X || !Y
+ // !(X || Y) => !X && !Y
+ private Pointcut distributeNot(Pointcut pc) {
+ if (isNot(pc)) {
+ NotPointcut npc = (NotPointcut) pc;
+ Pointcut notBody = distributeNot(npc.getNegatedPointcut());
+ if (isNot(notBody)) {
+ // !!X => X
+ return ((NotPointcut)notBody).getNegatedPointcut();
+ } else if (isAnd(notBody)) {
+ // !(X && Y) => !X || !Y
+ AndPointcut apc = (AndPointcut) notBody;
+ Pointcut newLeft = distributeNot(new NotPointcut(apc.getLeft()));
+ Pointcut newRight = distributeNot(new NotPointcut(apc.getRight()));
+ return new OrPointcut(newLeft,newRight);
+ } else if (isOr(notBody)) {
+ // !(X || Y) => !X && !Y
+ OrPointcut opc = (OrPointcut) notBody;
+ Pointcut newLeft = distributeNot(new NotPointcut(opc.getLeft()));
+ Pointcut newRight = distributeNot(new NotPointcut(opc.getRight()));
+ return new AndPointcut(newLeft,newRight);
+ } else {
+ return new NotPointcut(notBody);
+ }
+ } else if (isAnd(pc)) {
+ AndPointcut apc = (AndPointcut) pc;
+ Pointcut left = distributeNot(apc.getLeft());
+ Pointcut right = distributeNot(apc.getRight());
+ return new AndPointcut(left,right);
+ } else if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ Pointcut left = distributeNot(opc.getLeft());
+ Pointcut right = distributeNot(opc.getRight());
+ return new OrPointcut(left,right);
+ } else {
+ return pc;
+ }
+ }
+
+ // A && (B || C) => (A && B) || (A && C)
+ // (A || B) && C => (A && C) || (B && C)
+ private Pointcut pullUpDisjunctions(Pointcut pc) {
+ if (isNot(pc)) {
+ NotPointcut npc = (NotPointcut)pc;
+ return new NotPointcut(pullUpDisjunctions(npc.getNegatedPointcut()));
+ } else if (isAnd(pc)) {
+ AndPointcut apc = (AndPointcut) pc;
+ // dive into left and right here...
+ Pointcut left = pullUpDisjunctions(apc.getLeft());
+ Pointcut right = pullUpDisjunctions(apc.getRight());
+ if (isOr(left) && !isOr(right)) {
+ // (A || B) && C => (A && C) || (B && C)
+ Pointcut leftLeft = ((OrPointcut)left).getLeft();
+ Pointcut leftRight = ((OrPointcut)left).getRight();
+ return new OrPointcut(
+ new AndPointcut(leftLeft,right),
+ new AndPointcut(leftRight,right));
+ } else if (isOr(right) && !isOr(left)) {
+ // A && (B || C) => (A && B) || (A && C)
+ Pointcut rightLeft = ((OrPointcut)right).getLeft();
+ Pointcut rightRight = ((OrPointcut)right).getRight();
+ return new OrPointcut(
+ new AndPointcut(left,rightLeft),
+ new AndPointcut(left,rightRight));
+
+ } else {
+ return new AndPointcut(left,right);
+ }
+ } else if (isOr(pc)){
+ OrPointcut opc = (OrPointcut) pc;
+ return new OrPointcut(pullUpDisjunctions(opc.getLeft()),
+ pullUpDisjunctions(opc.getRight()));
+ } else {
+ return pc;
+ }
+ }
+
+ // NOT: execution(* TP.*(..)) => within(TP) && execution(* *(..))
+ // since this breaks when the pattern matches an interface
+ // NOT: withincode(* TP.*(..)) => within(TP) && withincode(* *(..))
+ // since this is not correct when an aspect makes an ITD
+// private Pointcut splitOutWithins(Pointcut pc) {
+// if (isExecution(pc)) {
+// KindedPointcut kpc = (KindedPointcut) pc;
+// SignaturePattern sp = kpc.signature;
+// TypePattern within = sp.getDeclaringType();
+// if (isAnyType(within)) return pc;
+// SignaturePattern simplified = removeDeclaringTypePattern(sp);
+// return new AndPointcut(new WithinPointcut(within),
+// new KindedPointcut(kpc.kind,simplified));
+// } else if (isNot(pc)) {
+// return new NotPointcut(splitOutWithins(((NotPointcut)pc).getNegatedPointcut()));
+// } else if (isAnd(pc)) {
+// AndPointcut apc = (AndPointcut) pc;
+// return new AndPointcut(splitOutWithins(apc.getLeft()),
+// splitOutWithins(apc.getRight()));
+// } else if (isOr(pc)) {
+// OrPointcut opc = (OrPointcut) pc;
+// return new OrPointcut(splitOutWithins(opc.getLeft()),
+// splitOutWithins(opc.getRight()));
+// } else {
+// return pc;
+// }
+// }
+
+ private SignaturePattern removeDeclaringTypePattern(SignaturePattern sp) {
+ return new SignaturePattern(
+ sp.getKind(),
+ sp.getModifiers(),
+ sp.getReturnType(),
+ TypePattern.ANY,
+ sp.getName(),
+ sp.getParameterTypes(),
+ sp.getThrowsPattern(),
+ sp.getAnnotationPattern()
+ );
+ }
+
+ // this finds the root of each && tree and then aggregates all of the branches
+ // into a sorted set:
+ // - duplicates are removed
+ // - A && !A is replaced by a matchesNothingPointcut
+ // - the kind(s) matched by the set are evaluated
+ // - elements are sorted by evaluation complexity
+ // - the result is written out with the least expensive branch leftmost
+ private Pointcut simplifyAnds(Pointcut pc) {
+ if (isNot(pc)) {
+ NotPointcut npc = (NotPointcut) pc;
+ return new NotPointcut(simplifyAnds(npc.getNegatedPointcut()));
+ } else if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ return new OrPointcut(simplifyAnds(opc.getLeft()),simplifyAnds(opc.getRight()));
+ } else if (isAnd(pc)) {
+ return simplifyAnd((AndPointcut)pc);
+ } else {
+ return pc;
+ }
+ }
+
+ private Pointcut simplifyAnd(AndPointcut apc) {
+ SortedSet nodes = new TreeSet(new PointcutEvaluationExpenseComparator());
+ collectAndNodes(apc,nodes);
+ // look for A and !A, or IfFalse
+ for (Iterator iter = nodes.iterator(); iter.hasNext();) {
+ Pointcut element = (Pointcut) iter.next();
+ if (element instanceof NotPointcut) {
+ Pointcut body = ((NotPointcut)element).getNegatedPointcut();
+ if (nodes.contains(body)) return Pointcut.makeMatchesNothing(body.state);
+ }
+ if (element instanceof IfPointcut) {
+ if (((IfPointcut)element).alwaysFalse()) return Pointcut.makeMatchesNothing(element.state);
+ }
+ if (element.toString().equals("")) return element; // matches nothing...
+ }
+ if (apc.couldMatchKinds().isEmpty()) return Pointcut.makeMatchesNothing(apc.state);
+ // write out with cheapest on left
+ Iterator iter = nodes.iterator();
+ Pointcut result = (Pointcut) iter.next();
+ while(iter.hasNext()) {
+ Pointcut right = (Pointcut) iter.next();
+ result = new AndPointcut(result,right);
+ }
+ return result;
+ }
+
+ private Pointcut sortOrs(Pointcut pc) {
+ SortedSet nodes = new TreeSet(new PointcutEvaluationExpenseComparator());
+ collectOrNodes(pc,nodes);
+ // write out with cheapest on left
+ Iterator iter = nodes.iterator();
+ Pointcut result = (Pointcut) iter.next();
+ while(iter.hasNext()) {
+ Pointcut right = (Pointcut) iter.next();
+ result = new OrPointcut(result,right);
+ }
+ return result;
+ }
+
+ private void collectAndNodes(AndPointcut apc,Set nodesSoFar) {
+ Pointcut left = apc.getLeft();
+ Pointcut right = apc.getRight();
+ if (isAnd(left)) {
+ collectAndNodes((AndPointcut)left,nodesSoFar);
+ } else {
+ nodesSoFar.add(left);
+ }
+ if (isAnd(right)) {
+ collectAndNodes((AndPointcut)right,nodesSoFar);
+ } else {
+ nodesSoFar.add(right);
+ }
+ }
+
+ private void collectOrNodes(Pointcut pc, Set nodesSoFar) {
+ if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ collectOrNodes(opc.getLeft(),nodesSoFar);
+ collectOrNodes(opc.getRight(),nodesSoFar);
+ } else {
+ nodesSoFar.add(pc);
+ }
+ }
+
+ private boolean isNot(Pointcut pc) {
+ return (pc instanceof NotPointcut);
+ }
+
+ private boolean isAnd(Pointcut pc) {
+ return (pc instanceof AndPointcut);
+ }
+
+ private boolean isOr(Pointcut pc) {
+ return (pc instanceof OrPointcut);
+ }
+
+ private boolean isExecution(Pointcut pc) {
+ if (pc instanceof KindedPointcut) {
+ KindedPointcut kp = (KindedPointcut) pc;
+ if (kp.kind == Shadow.MethodExecution) return true;
+ if (kp.kind == Shadow.ConstructorExecution) return true;
+ }
+ return false;
+ }
+
+ private boolean isWithinCode(Pointcut pc) {
+ return (pc instanceof WithincodePointcut);
+ }
+
+ private boolean isAnyType(TypePattern tp) {
+ if (tp == TypePattern.ANY) return true;
+ if (tp.toString().equals("*")) return true;
+ return false;
+ }
+} \ No newline at end of file
diff --git a/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java b/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java
index 6b5d17721..ded642b4e 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java
@@ -17,6 +17,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.MessageUtil;
@@ -58,6 +59,10 @@ public class ReferencePointcut extends Pointcut {
this.pointcutKind = REFERENCE;
}
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
//??? do either of these match methods make any sense???
public FuzzyBoolean fastMatch(FastMatchInfo type) {
@@ -67,7 +72,7 @@ public class ReferencePointcut extends Pointcut {
/**
* Do I really match this shadow?
*/
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return FuzzyBoolean.NO;
}
@@ -210,7 +215,7 @@ public class ReferencePointcut extends Pointcut {
arguments.postRead(enclosingType);
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
throw new RuntimeException("shouldn't happen");
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java
index 7c51135f7..f48cd76ae 100644
--- a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java
@@ -488,6 +488,7 @@ public class SignaturePattern extends PatternNode {
&& o.declaringType.equals(this.declaringType)
&& o.name.equals(this.name)
&& o.parameterTypes.equals(this.parameterTypes)
+ && o.throwsPattern.equals(this.throwsPattern)
&& o.annotationPattern.equals(this.annotationPattern);
}
public int hashCode() {
@@ -498,6 +499,7 @@ public class SignaturePattern extends PatternNode {
result = 37*result + declaringType.hashCode();
result = 37*result + name.hashCode();
result = 37*result + parameterTypes.hashCode();
+ result = 37*result + throwsPattern.hashCode();
result = 37*result + annotationPattern.hashCode();
return result;
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java
index 946cdc99c..189eeac12 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java
@@ -12,6 +12,12 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
@@ -41,6 +47,15 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
private boolean alreadyWarnedAboutDEoW = false;
private ExactAnnotationTypePattern annotationTypePattern;
private ShadowMunger munger;
+ private static final Set thisKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+ private static final Set targetKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+ static {
+ for (Iterator iter = Shadow.ALL_SHADOW_KINDS.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ if (kind.neverHasThis()) thisKindSet.remove(kind);
+ if (kind.neverHasTarget()) targetKindSet.remove(kind);
+ }
+ }
/**
*
@@ -56,6 +71,10 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
this.munger = munger;
}
+ public Set couldMatchKinds() {
+ return isThis ? thisKindSet : targetKindSet;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
*/
@@ -66,7 +85,7 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
*/
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
if (!couldMatch(shadow)) return FuzzyBoolean.NO;
ResolvedTypeX toMatchAgainst =
(isThis ? shadow.getThisType() : shadow.getTargetType() ).resolve(shadow.getIWorld());
@@ -136,7 +155,7 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
*/
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
if (!couldMatch(shadow)) return Literal.FALSE;
boolean alwaysMatches = match(shadow).alwaysTrue();
Var var = isThis ? shadow.getThisVar() : shadow.getTargetVar();
@@ -149,15 +168,15 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
shadow.getTargetAnnotationVar(annotationType);
if (annVar == null) return Literal.TRUE; // should be exception when we implement properly
// Check if we have already bound something to this formal
- if (state.get(btp.getFormalIndex())!=null) {
- ISourceLocation pcdSloc = getSourceLocation();
- ISourceLocation shadowSloc = shadow.getSourceLocation();
- Message errorMessage = new Message(
- "Cannot use @pointcut to match at this location and bind a formal to type '"+annVar.getType()+
- "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
- ". The secondary source location points to the problematic binding.",
- shadowSloc,true,new ISourceLocation[]{pcdSloc});
- shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
+ if ((state.get(btp.getFormalIndex())!=null) &&(lastMatchedShadowId == shadow.shadowId)) {
+// ISourceLocation pcdSloc = getSourceLocation();
+// ISourceLocation shadowSloc = shadow.getSourceLocation();
+// Message errorMessage = new Message(
+// "Cannot use @pointcut to match at this location and bind a formal to type '"+annVar.getType()+
+// "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
+// ". The secondary source location points to the problematic binding.",
+// shadowSloc,true,new ISourceLocation[]{pcdSloc});
+// shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
state.setErroneousVar(btp.getFormalIndex());
}
state.set(btp.getFormalIndex(),annVar);
@@ -181,6 +200,25 @@ public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
return isThis ? shadow.hasThis() : shadow.hasTarget();
}
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ public List getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ List l = new ArrayList();
+ l.add(annotationTypePattern);
+ return l;
+ } else return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ public List getBindingTypePatterns() {
+ return Collections.EMPTY_LIST;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
*/
diff --git a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java
index 4530c933a..c655d1d61 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java
@@ -17,6 +17,12 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
@@ -50,7 +56,17 @@ import org.aspectj.weaver.ast.Var;
public class ThisOrTargetPointcut extends NameBindingPointcut {
private boolean isThis;
private TypePattern type;
-
+
+ private static final Set thisKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+ private static final Set targetKindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+ static {
+ for (Iterator iter = Shadow.ALL_SHADOW_KINDS.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ if (kind.neverHasThis()) thisKindSet.remove(kind);
+ if (kind.neverHasTarget()) targetKindSet.remove(kind);
+ }
+ }
+
public ThisOrTargetPointcut(boolean isThis, TypePattern type) {
this.isThis = isThis;
this.type = type;
@@ -58,7 +74,11 @@ public class ThisOrTargetPointcut extends NameBindingPointcut {
}
public boolean isThis() { return isThis; }
-
+
+ public Set couldMatchKinds() {
+ return isThis ? thisKindSet : targetKindSet;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
@@ -67,7 +87,7 @@ public class ThisOrTargetPointcut extends NameBindingPointcut {
return isThis ? shadow.hasThis() : shadow.hasTarget();
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
if (!couldMatch(shadow)) return FuzzyBoolean.NO;
TypeX typeToMatch = isThis ? shadow.getThisType() : shadow.getTargetType();
//if (typeToMatch == ResolvedTypeX.MISSING) return FuzzyBoolean.NO;
@@ -131,6 +151,25 @@ public class ThisOrTargetPointcut extends NameBindingPointcut {
type.postRead(enclosingType);
}
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ public List getBindingAnnotationTypePatterns() {
+ return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ public List getBindingTypePatterns() {
+ if (type instanceof BindingTypePattern) {
+ List l = new ArrayList();
+ l.add(type);
+ return l;
+ } else return Collections.EMPTY_LIST;
+ }
+
+
public boolean equals(Object other) {
if (!(other instanceof ThisOrTargetPointcut)) return false;
ThisOrTargetPointcut o = (ThisOrTargetPointcut)other;
@@ -146,7 +185,7 @@ public class ThisOrTargetPointcut extends NameBindingPointcut {
return (isThis ? "this(" : "target(") + type + ")";
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
if (!couldMatch(shadow)) return Literal.FALSE;
if (type == TypePattern.ANY) return Literal.TRUE;
@@ -156,15 +195,15 @@ public class ThisOrTargetPointcut extends NameBindingPointcut {
if (type instanceof BindingTypePattern) {
BindingTypePattern btp = (BindingTypePattern)type;
// Check if we have already bound something to this formal
- if (state.get(btp.getFormalIndex())!=null) {
- ISourceLocation pcdSloc = getSourceLocation();
- ISourceLocation shadowSloc = shadow.getSourceLocation();
- Message errorMessage = new Message(
- "Cannot use "+(isThis?"this()":"target()")+" to match at this location and bind a formal to type '"+var.getType()+
- "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
- ". The secondary source location points to the problematic "+(isThis?"this()":"target()")+".",
- shadowSloc,true,new ISourceLocation[]{pcdSloc});
- shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
+ if ((state.get(btp.getFormalIndex())!=null) && (lastMatchedShadowId != shadow.shadowId)){
+// ISourceLocation pcdSloc = getSourceLocation();
+// ISourceLocation shadowSloc = shadow.getSourceLocation();
+// Message errorMessage = new Message(
+// "Cannot use "+(isThis?"this()":"target()")+" to match at this location and bind a formal to type '"+var.getType()+
+// "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
+// ". The secondary source location points to the problematic "+(isThis?"this()":"target()")+".",
+// shadowSloc,true,new ISourceLocation[]{pcdSloc});
+// shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
state.setErroneousVar(btp.getFormalIndex());
//return null;
}
@@ -186,7 +225,9 @@ public class ThisOrTargetPointcut extends NameBindingPointcut {
inAspect.crosscuttingMembers.exposeType(newType.getExactType());
}
- return new ThisOrTargetPointcut(isThis, newType);
+ Pointcut ret = new ThisOrTargetPointcut(isThis, newType);
+ ret.copyLocationFrom(this);
+ return ret;
}
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java b/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java
index dd95137ec..5af1c4049 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java
@@ -49,8 +49,9 @@ public class ThrowsPattern extends PatternNode {
public boolean equals(Object other) {
if (!(other instanceof ThrowsPattern)) return false;
ThrowsPattern o = (ThrowsPattern)other;
- return o.required.equals(this.required) &&
+ boolean ret = o.required.equals(this.required) &&
o.forbidden.equals(this.forbidden);
+ return ret;
}
public int hashCode() {
int result = 17;
diff --git a/weaver/src/org/aspectj/weaver/patterns/TypePattern.java b/weaver/src/org/aspectj/weaver/patterns/TypePattern.java
index 0596bb1e9..1295be59d 100644
--- a/weaver/src/org/aspectj/weaver/patterns/TypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/TypePattern.java
@@ -319,6 +319,20 @@ class EllipsisTypePattern extends TypePattern {
}
public String toString() { return ".."; }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ return (obj instanceof EllipsisTypePattern);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return 17 * 37;
+ }
}
class AnyTypePattern extends TypePattern {
@@ -385,6 +399,14 @@ class AnyTypePattern extends TypePattern {
}
public String toString() { return "*"; }
+
+ public boolean equals(Object obj) {
+ return (obj instanceof AnyTypePattern);
+ }
+
+ public int hashCode() {
+ return 37;
+ }
}
class NoTypePattern extends TypePattern {
@@ -447,5 +469,19 @@ class NoTypePattern extends TypePattern {
}
public String toString() { return "<nothing>"; }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ return (obj instanceof NoTypePattern);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return 17 * 37 * 37;
+ }
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
index 4e7dc4b79..02344c47e 100644
--- a/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
+++ b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java
@@ -532,6 +532,9 @@ public class WildTypePattern extends TypePattern {
WildTypePattern o = (WildTypePattern)other;
int len = o.namePatterns.length;
if (len != this.namePatterns.length) return false;
+ if (this.includeSubtypes != o.includeSubtypes) return false;
+ if (this.dim != o.dim) return false;
+ if (this.isVarArgs != o.isVarArgs) return false;
for (int i=0; i < len; i++) {
if (!o.namePatterns[i].equals(this.namePatterns[i])) return false;
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java b/weaver/src/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java
index 76bf81abe..bc65e609e 100644
--- a/weaver/src/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java
@@ -12,6 +12,10 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
@@ -52,6 +56,10 @@ public class WithinAnnotationPointcut extends NameBindingPointcut {
this.munger = munger;
}
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
*/
@@ -62,7 +70,7 @@ public class WithinAnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
*/
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
ResolvedTypeX enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(),true);
if (enclosingType == ResolvedTypeX.MISSING) {
IMessage msg = new Message(
@@ -104,22 +112,22 @@ public class WithinAnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
*/
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern)annotationTypePattern;
TypeX annotationType = btp.annotationType;
Var var = shadow.getWithinAnnotationVar(annotationType);
if (var == null) return Literal.FALSE;
// Check if we have already bound something to this formal
- if (state.get(btp.getFormalIndex())!=null) {
- ISourceLocation pcdSloc = getSourceLocation();
- ISourceLocation shadowSloc = shadow.getSourceLocation();
- Message errorMessage = new Message(
- "Cannot use @pointcut to match at this location and bind a formal to type '"+var.getType()+
- "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
- ". The secondary source location points to the problematic binding.",
- shadowSloc,true,new ISourceLocation[]{pcdSloc});
- shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
+ if ((state.get(btp.getFormalIndex())!=null) &&(lastMatchedShadowId == shadow.shadowId)) {
+// ISourceLocation pcdSloc = getSourceLocation();
+// ISourceLocation shadowSloc = shadow.getSourceLocation();
+// Message errorMessage = new Message(
+// "Cannot use @pointcut to match at this location and bind a formal to type '"+var.getType()+
+// "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
+// ". The secondary source location points to the problematic binding.",
+// shadowSloc,true,new ISourceLocation[]{pcdSloc});
+// shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
state.setErroneousVar(btp.getFormalIndex());
}
state.set(btp.getFormalIndex(),var);
@@ -128,6 +136,24 @@ public class WithinAnnotationPointcut extends NameBindingPointcut {
}
/* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ public List getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ List l = new ArrayList();
+ l.add(annotationTypePattern);
+ return l;
+ } else return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ public List getBindingTypePatterns() {
+ return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
* @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
*/
public void write(DataOutputStream s) throws IOException {
diff --git a/weaver/src/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java b/weaver/src/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java
index c51d7008b..4eb6473e3 100644
--- a/weaver/src/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java
@@ -12,6 +12,11 @@ package org.aspectj.weaver.patterns;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
@@ -40,6 +45,14 @@ public class WithinCodeAnnotationPointcut extends NameBindingPointcut {
private ExactAnnotationTypePattern annotationTypePattern;
private ShadowMunger munger = null; // only set after concretization
+ private static final Set matchedShadowKinds = new HashSet();
+ static {
+ matchedShadowKinds.addAll(Shadow.ALL_SHADOW_KINDS);
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (Shadow.SHADOW_KINDS[i].isEnclosingKind())
+ matchedShadowKinds.remove(Shadow.SHADOW_KINDS[i]);
+ }
+ }
public WithinCodeAnnotationPointcut(ExactAnnotationTypePattern type) {
super();
@@ -52,6 +65,10 @@ public class WithinCodeAnnotationPointcut extends NameBindingPointcut {
this.munger = munger;
}
+ public Set couldMatchKinds() {
+ return matchedShadowKinds;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
*/
@@ -62,7 +79,7 @@ public class WithinCodeAnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
*/
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
AnnotatedElement toMatchAgainst = null;
Member member = shadow.getEnclosingCodeSignature();
ResolvedMember rMember = member.resolve(shadow.getIWorld());
@@ -109,7 +126,7 @@ public class WithinCodeAnnotationPointcut extends NameBindingPointcut {
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
*/
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern)annotationTypePattern;
@@ -117,15 +134,15 @@ public class WithinCodeAnnotationPointcut extends NameBindingPointcut {
Var var = shadow.getWithinCodeAnnotationVar(annotationType);
if (var == null) return Literal.FALSE;
// Check if we have already bound something to this formal
- if (state.get(btp.getFormalIndex())!=null) {
- ISourceLocation pcdSloc = getSourceLocation();
- ISourceLocation shadowSloc = shadow.getSourceLocation();
- Message errorMessage = new Message(
- "Cannot use @pointcut to match at this location and bind a formal to type '"+var.getType()+
- "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
- ". The secondary source location points to the problematic binding.",
- shadowSloc,true,new ISourceLocation[]{pcdSloc});
- shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
+ if ((state.get(btp.getFormalIndex())!=null) &&(lastMatchedShadowId == shadow.shadowId)) {
+// ISourceLocation pcdSloc = getSourceLocation();
+// ISourceLocation shadowSloc = shadow.getSourceLocation();
+// Message errorMessage = new Message(
+// "Cannot use @pointcut to match at this location and bind a formal to type '"+var.getType()+
+// "' - the formal is already bound to type '"+state.get(btp.getFormalIndex()).getType()+"'"+
+// ". The secondary source location points to the problematic binding.",
+// shadowSloc,true,new ISourceLocation[]{pcdSloc});
+// shadow.getIWorld().getMessageHandler().handleMessage(errorMessage);
state.setErroneousVar(btp.getFormalIndex());
}
state.set(btp.getFormalIndex(),var);
@@ -133,6 +150,25 @@ public class WithinCodeAnnotationPointcut extends NameBindingPointcut {
return Literal.TRUE;
}
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ public List getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ List l = new ArrayList();
+ l.add(annotationTypePattern);
+ return l;
+ } else return Collections.EMPTY_LIST;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ public List getBindingTypePatterns() {
+ return Collections.EMPTY_LIST;
+ }
+
/* (non-Javadoc)
* @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
*/
diff --git a/weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java b/weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java
index 50181a6c7..edda70510 100644
--- a/weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java
@@ -17,6 +17,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
@@ -48,12 +49,16 @@ public class WithinPointcut extends Pointcut {
}
return FuzzyBoolean.NO;
}
+
+ public Set couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS;
+ }
public FuzzyBoolean fastMatch(FastMatchInfo info) {
return isWithinType(info.getType());
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
ResolvedTypeX enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(),true);
if (enclosingType == ResolvedTypeX.MISSING) {
IMessage msg = new Message(
@@ -146,12 +151,14 @@ public class WithinPointcut extends Pointcut {
return "within(" + typePattern + ")";
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
}
public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
- return new WithinPointcut(typePattern);
+ Pointcut ret = new WithinPointcut(typePattern);
+ ret.copyLocationFrom(this);
+ return ret;
}
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java b/weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java
index 8778a679e..2de912cc4 100644
--- a/weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java
@@ -17,6 +17,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Member;
+import java.util.HashSet;
+import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.runtime.reflect.Factory;
@@ -30,17 +32,32 @@ import org.aspectj.weaver.ast.Test;
public class WithincodePointcut extends Pointcut {
SignaturePattern signature;
+ private static final Set matchedShadowKinds = new HashSet();
+ static {
+ matchedShadowKinds.addAll(Shadow.ALL_SHADOW_KINDS);
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (Shadow.SHADOW_KINDS[i].isEnclosingKind())
+ matchedShadowKinds.remove(Shadow.SHADOW_KINDS[i]);
+ }
+ // these next two are needed for inlining of field initializers
+ matchedShadowKinds.add(Shadow.ConstructorExecution);
+ matchedShadowKinds.add(Shadow.Initialization);
+ }
public WithincodePointcut(SignaturePattern signature) {
this.signature = signature;
this.pointcutKind = WITHINCODE;
}
-
+
+ public Set couldMatchKinds() {
+ return matchedShadowKinds;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
//This will not match code in local or anonymous classes as if
//they were withincode of the outer signature
return FuzzyBoolean.fromBoolean(
@@ -107,12 +124,14 @@ public class WithincodePointcut extends Pointcut {
return "withincode(" + signature + ")";
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
}
public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
- return new WithincodePointcut(signature);
+ Pointcut ret = new WithincodePointcut(signature);
+ ret.copyLocationFrom(this);
+ return ret;
}
}
diff --git a/weaver/src/org/aspectj/weaver/weaver-messages.properties b/weaver/src/org/aspectj/weaver/weaver-messages.properties
index e3e7c9c7f..e33fa4557 100644
--- a/weaver/src/org/aspectj/weaver/weaver-messages.properties
+++ b/weaver/src/org/aspectj/weaver/weaver-messages.properties
@@ -108,6 +108,12 @@ errorLoadingXLintDefault=problem loading XlintDefault.properties, {0}
invalidXLintKey=invalid Xlint key: {0}
invalidXLintMessageKind=invalid Xlint message kind (must be one of ignore, warning, error): {0}
+# Binding of formals
+unboundFormalInPC=the parameter {0} is not bound in [all branches of] pointcut
+ambiguousBindingInPC=the binding of parameter {0} is ambiguous in pointcut
+ambiguousBindingInOrPC=ambiguous binding of parameter(s) {0} across ''||'' in pointcut
+negationDoesntAllowBinding=cannot bind a parameter in a negated expression
+
# Java5
# Enum
diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java b/weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java
index 71f35d6df..f093740d9 100644
--- a/weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java
+++ b/weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java
@@ -39,6 +39,7 @@ public class PatternsTests extends TestCase {
suite.addTestSuite(WithinCodeTestCase.class);
suite.addTestSuite(AnnotationPatternTestCase.class);
suite.addTestSuite(AnnotationPatternMatchingTestCase.class);
+ suite.addTestSuite(PointcutRewriterTest.class);
//$JUnit-END$
return suite;
}
diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/PointcutRewriterTest.java b/weaver/testsrc/org/aspectj/weaver/patterns/PointcutRewriterTest.java
new file mode 100644
index 000000000..c208c621d
--- /dev/null
+++ b/weaver/testsrc/org/aspectj/weaver/patterns/PointcutRewriterTest.java
@@ -0,0 +1,366 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * 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
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.aspectj.weaver.Shadow;
+
+import junit.framework.TestCase;
+
+/**
+ * @author colyer
+ *
+ * TODO To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+public class PointcutRewriterTest extends TestCase {
+
+ private PointcutRewriter prw;
+
+ public void testDistributeNot() {
+ Pointcut plain = getPointcut("this(Foo)");
+ assertEquals("Unchanged",plain,prw.rewrite(plain));
+ Pointcut not = getPointcut("!this(Foo)");
+ assertEquals("Unchanged",not,prw.rewrite(not));
+ Pointcut notNot = getPointcut("!!this(Foo)");
+ assertEquals("this(Foo)",prw.rewrite(notNot).toString());
+ Pointcut notNotNOT = getPointcut("!!!this(Foo)");
+ assertEquals("!this(Foo)",prw.rewrite(notNotNOT).toString());
+ Pointcut and = getPointcut("!(this(Foo) && this(Goo))");
+ assertEquals("(!this(Foo) || !this(Goo))",prw.rewrite(and).toString());
+ Pointcut or = getPointcut("!(this(Foo) || this(Goo))");
+ assertEquals("(!this(Foo) && !this(Goo))",prw.rewrite(or).toString());
+ Pointcut nestedNot = getPointcut("!(this(Foo) && !this(Goo))");
+ assertEquals("(!this(Foo) || this(Goo))",prw.rewrite(nestedNot).toString());
+ }
+
+ public void testPullUpDisjunctions() {
+ Pointcut aAndb = getPointcut("this(Foo) && this(Goo)");
+ assertEquals("Unchanged",aAndb,prw.rewrite(aAndb));
+ Pointcut aOrb = getPointcut("this(Foo) || this(Moo)");
+ assertEquals("Unchanged",aOrb,prw.rewrite(aOrb));
+ Pointcut leftOr = getPointcut("this(Foo) || (this(Goo) && this(Boo))");
+ System.out.println(prw.rewrite(leftOr));
+ assertEquals("(this(Foo) || (this(Boo) && this(Goo)))",prw.rewrite(leftOr).toString());
+ Pointcut rightOr = getPointcut("(this(Goo) && this(Boo)) || this(Foo)");
+ assertEquals("(this(Foo) || (this(Boo) && this(Goo)))",prw.rewrite(rightOr).toString());
+ Pointcut leftAnd = getPointcut("this(Foo) && (this(Goo) || this(Boo))");
+ assertEquals("((this(Boo) && this(Foo)) || (this(Foo) && this(Goo)))",prw.rewrite(leftAnd).toString());
+ Pointcut rightAnd = getPointcut("(this(Goo) || this(Boo)) && this(Foo)");
+ assertEquals("((this(Boo) && this(Foo)) || (this(Foo) && this(Goo)))",prw.rewrite(rightAnd).toString());
+ Pointcut nestedOrs = getPointcut("this(Foo) || this(Goo) || this(Boo)");
+ assertEquals("((this(Boo) || this(Foo)) || this(Goo))",prw.rewrite(nestedOrs).toString());
+ Pointcut nestedAnds = getPointcut("(this(Foo) && (this(Boo) && (this(Goo) || this(Moo))))");
+ // t(F) && (t(B) && (t(G) || t(M)))
+ // ==> t(F) && ((t(B) && t(G)) || (t(B) && t(M)))
+ // ==> (t(F) && (t(B) && t(G))) || (t(F) && (t(B) && t(M)))
+ assertEquals("(((this(Boo) && this(Foo)) && this(Goo)) || ((this(Boo) && this(Foo)) && this(Moo)))",
+ prw.rewrite(nestedAnds).toString());
+ }
+
+
+// public void testSplitOutWithins() {
+// Pointcut simpleExecution = getPointcut("execution(* *.*(..))");
+// assertEquals("Unchanged",simpleExecution,prw.rewrite(simpleExecution));
+// Pointcut simpleWithinCode = getPointcut("withincode(* *.*(..))");
+// assertEquals("Unchanged",simpleWithinCode,prw.rewrite(simpleWithinCode));
+// Pointcut execution = getPointcut("execution(@Foo Foo (@Goo org.xyz..*).m*(Foo,Boo))");
+// assertEquals("(within((@(Goo) org.xyz..*)) && execution(@(Foo) Foo m*(Foo, Boo)))",
+// prw.rewrite(execution).toString());
+// Pointcut withincode = getPointcut("withincode(@Foo Foo (@Goo org.xyz..*).m*(Foo,Boo))");
+// assertEquals("(within((@(Goo) org.xyz..*)) && withincode(@(Foo) Foo m*(Foo, Boo)))",
+// prw.rewrite(withincode).toString());
+// Pointcut notExecution = getPointcut("!execution(Foo BankAccount+.*(..))");
+// assertEquals("(!within(BankAccount+) || !execution(Foo *(..)))",
+// prw.rewrite(notExecution).toString());
+// Pointcut andWithincode = getPointcut("withincode(Foo.new(..)) && this(Foo)");
+// assertEquals("((within(Foo) && withincode(new(..))) && this(Foo))",
+// prw.rewrite(andWithincode).toString());
+// Pointcut orExecution = getPointcut("this(Foo) || execution(Goo Foo.moo(Baa))");
+// assertEquals("((within(Foo) && execution(Goo moo(Baa))) || this(Foo))",
+// prw.rewrite(orExecution).toString());
+// }
+
+
+ public void testRemoveDuplicatesInAnd() {
+ Pointcut dupAnd = getPointcut("this(Foo) && this(Foo)");
+ assertEquals("this(Foo)",prw.rewrite(dupAnd).toString());
+ Pointcut splitdupAnd = getPointcut("(this(Foo) && target(Boo)) && this(Foo)");
+ assertEquals("(target(Boo) && this(Foo))",prw.rewrite(splitdupAnd).toString());
+ }
+
+ public void testNotRemoveNearlyDuplicatesInAnd() {
+ Pointcut toAndto = getPointcut("this(Object+) && this(Object)");
+ Pointcut rewritten = prw.rewrite(toAndto);
+ }
+
+ public void testAAndNotAinAnd() {
+ Pointcut aAndNota = getPointcut("this(Foo)&& !this(Foo)");
+ assertEquals("Matches nothing","",prw.rewrite(aAndNota).toString());
+ Pointcut aAndBAndNota = getPointcut("this(Foo) && execution(* *.*(..)) && !this(Foo)");
+ assertEquals("Matches nothing","",prw.rewrite(aAndBAndNota).toString());
+ }
+
+ public void testIfFalseInAnd() {
+ Pointcut ifFalse = IfPointcut.makeIfFalsePointcut(Pointcut.CONCRETE);
+ Pointcut p = getPointcut("this(A)");
+ assertEquals("Matches nothing","",prw.rewrite(new AndPointcut(ifFalse,p)).toString());
+ }
+
+ public void testMatchesNothinginAnd() {
+ Pointcut nothing = Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ Pointcut p = getPointcut("this(A)");
+ assertEquals("Matches nothing","",prw.rewrite(new AndPointcut(nothing,p)).toString());
+ }
+
+ public void testMixedKindsInAnd() {
+ Pointcut mixedKinds = getPointcut("call(* *(..)) && execution(* *(..))");
+ assertEquals("Matches nothing","",prw.rewrite(mixedKinds).toString());
+ Pointcut ok = getPointcut("call(* *(..)) && this(Foo)");
+ assertEquals(ok,prw.rewrite(ok));
+ }
+
+ public void testDetermineKindSetOfAnd() {
+ Pointcut oneKind = getPointcut("execution(* foo(..)) && this(Boo)");
+ AndPointcut rewritten = (AndPointcut) prw.rewrite(oneKind);
+ assertEquals("Only one kind",1,rewritten.couldMatchKinds().size());
+ assertTrue("It's Shadow.MethodExecution",rewritten.couldMatchKinds().contains(Shadow.MethodExecution));
+ }
+
+ public void testKindSetOfExecution() {
+ Pointcut p = getPointcut("execution(* foo(..))");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.MethodExecution",p.couldMatchKinds().contains(Shadow.MethodExecution));
+ p = getPointcut("execution(new(..))");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.ConstructorExecution",p.couldMatchKinds().contains(Shadow.ConstructorExecution));
+ }
+
+ public void testKindSetOfCall() {
+ Pointcut p = getPointcut("call(* foo(..))");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.MethodCall",p.couldMatchKinds().contains(Shadow.MethodCall));
+ p = getPointcut("call(new(..))");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.ConstructorCall",p.couldMatchKinds().contains(Shadow.ConstructorCall));
+ }
+
+ public void testKindSetOfAdviceExecution() {
+ Pointcut p = getPointcut("adviceexecution()");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.AdviceExecution",p.couldMatchKinds().contains(Shadow.AdviceExecution));
+ }
+
+ public void testKindSetOfGet() {
+ Pointcut p = getPointcut("get(* *)");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.FieldGet",p.couldMatchKinds().contains(Shadow.FieldGet));
+ }
+
+ public void testKindSetOfSet() {
+ Pointcut p = getPointcut("set(* *)");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.FieldSet",p.couldMatchKinds().contains(Shadow.FieldSet));
+ }
+
+ public void testKindSetOfHandler() {
+ Pointcut p = getPointcut("handler(*)");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.ExceptionHandler",p.couldMatchKinds().contains(Shadow.ExceptionHandler));
+ }
+
+ public void testKindSetOfInitialization() {
+ Pointcut p = getPointcut("initialization(new (..))");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.Initialization",p.couldMatchKinds().contains(Shadow.Initialization));
+ }
+
+ public void testKindSetOfPreInitialization() {
+ Pointcut p = getPointcut("preinitialization(new (..))");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.PreInitialization",p.couldMatchKinds().contains(Shadow.PreInitialization));
+ }
+
+ public void testKindSetOfStaticInitialization() {
+ Pointcut p = getPointcut("staticinitialization(*)");
+ assertEquals("Only one kind",1,p.couldMatchKinds().size());
+ assertTrue("It's Shadow.StaticInitialization",p.couldMatchKinds().contains(Shadow.StaticInitialization));
+ }
+
+ public void testKindSetOfThis() {
+ Pointcut p = getPointcut("this(Foo)");
+ Set matches = p.couldMatchKinds();
+ for (Iterator iter = matches.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ assertFalse("No kinds that don't have a this",kind.neverHasThis());
+ }
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (!Shadow.SHADOW_KINDS[i].neverHasThis()) {
+ assertTrue("All kinds that do have this",matches.contains(Shadow.SHADOW_KINDS[i]));
+ }
+ }
+ // + @
+ p = getPointcut("@this(@Foo)");
+ matches = p.couldMatchKinds();
+ for (Iterator iter = matches.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ assertFalse("No kinds that don't have a this",kind.neverHasThis());
+ }
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (!Shadow.SHADOW_KINDS[i].neverHasThis()) {
+ assertTrue("All kinds that do have this",matches.contains(Shadow.SHADOW_KINDS[i]));
+ }
+ }
+ }
+
+ public void testKindSetOfTarget() {
+ Pointcut p = getPointcut("target(Foo)");
+ Set matches = p.couldMatchKinds();
+ for (Iterator iter = matches.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ assertFalse("No kinds that don't have a target",kind.neverHasTarget());
+ }
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (!Shadow.SHADOW_KINDS[i].neverHasTarget()) {
+ assertTrue("All kinds that do have target",matches.contains(Shadow.SHADOW_KINDS[i]));
+ }
+ }
+ // + @
+ p = getPointcut("@target(@Foo)");
+ matches = p.couldMatchKinds();
+ for (Iterator iter = matches.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ assertFalse("No kinds that don't have a target",kind.neverHasTarget());
+ }
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (!Shadow.SHADOW_KINDS[i].neverHasTarget()) {
+ assertTrue("All kinds that do have target",matches.contains(Shadow.SHADOW_KINDS[i]));
+ }
+ }
+ }
+
+ public void testKindSetOfArgs() {
+ Pointcut p = getPointcut("args(..)");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ // + @
+ p = getPointcut("@args(..)");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ }
+
+ public void testKindSetOfAnnotation() {
+ Pointcut p = getPointcut("@annotation(@Foo)");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ }
+
+ public void testKindSetOfWithin() {
+ Pointcut p = getPointcut("within(*)");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ // + @
+ p = getPointcut("@within(@Foo)");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ }
+
+ public void testKindSetOfWithinCode() {
+ Pointcut p = getPointcut("withincode(* foo(..))");
+ Set matches = p.couldMatchKinds();
+ for (Iterator iter = matches.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ assertFalse("No kinds that are themselves enclosing",
+ (kind.isEnclosingKind() && kind != Shadow.ConstructorExecution && kind != Shadow.Initialization));
+ }
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (!Shadow.SHADOW_KINDS[i].isEnclosingKind()) {
+ assertTrue("All kinds that are not enclosing",matches.contains(Shadow.SHADOW_KINDS[i]));
+ }
+ }
+ assertTrue("Need cons-exe for inlined field inits",matches.contains(Shadow.ConstructorExecution));
+ assertTrue("Need init for inlined field inits",matches.contains(Shadow.Initialization));
+ // + @
+ p = getPointcut("@withincode(@Foo)");
+ matches = p.couldMatchKinds();
+ for (Iterator iter = matches.iterator(); iter.hasNext();) {
+ Shadow.Kind kind = (Shadow.Kind) iter.next();
+ assertFalse("No kinds that are themselves enclosing",kind.isEnclosingKind());
+ }
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (!Shadow.SHADOW_KINDS[i].isEnclosingKind()) {
+ assertTrue("All kinds that are not enclosing",matches.contains(Shadow.SHADOW_KINDS[i]));
+ }
+ }
+ }
+
+ public void testKindSetOfIf() {
+ Pointcut p = new IfPointcut(null,0);
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ p = IfPointcut.makeIfTruePointcut(Pointcut.CONCRETE);
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ p = IfPointcut.makeIfFalsePointcut(Pointcut.CONCRETE);
+ assertTrue("Nothing",p.couldMatchKinds().isEmpty());
+ }
+
+ public void testKindSetOfCflow() {
+ Pointcut p = getPointcut("cflow(this(Foo))");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ // [below]
+ p = getPointcut("cflowbelow(this(Foo))");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ }
+
+ public void testKindSetInNegation() {
+ Pointcut p = getPointcut("!execution(new(..))");
+ assertTrue("All kinds",p.couldMatchKinds().containsAll(Shadow.ALL_SHADOW_KINDS));
+ }
+
+ public void testKindSetOfOr() {
+ Pointcut p = getPointcut("execution(new(..)) || get(* *)");
+ Set matches = p.couldMatchKinds();
+ assertEquals("2 kinds",2,matches.size());
+ assertTrue("ConstructorExecution",matches.contains(Shadow.ConstructorExecution));
+ assertTrue("FieldGet",matches.contains(Shadow.FieldGet));
+ }
+
+ public void testOrderingInAnd() {
+ Pointcut bigLongPC = getPointcut("cflow(this(Foo)) && @args(@X) && args(X) && @this(@Foo) && @target(@Boo) && this(Moo) && target(Boo) && @annotation(@Moo) && @withincode(@Boo) && withincode(new(..)) && set(* *)&& @within(@Foo) && within(Foo)");
+ Pointcut rewritten = prw.rewrite(bigLongPC);
+ assertEquals("((((((((((((within(Foo) && @within(@Foo)) && set(* *)) && withincode(new(..))) && @withincode(@Boo)) && @annotation(@Moo)) && target(Boo)) && this(Moo)) && @target(@Boo)) && @this(@Foo)) && args(X)) && @args(@X)) && cflow(this(Foo)))",rewritten.toString());
+ }
+
+ public void testOrderingInSimpleOr() {
+ OrPointcut opc = (OrPointcut) getPointcut("execution(new(..)) || get(* *)");
+ assertEquals("reordered","(get(* *) || execution(new(..)))",prw.rewrite(opc).toString());
+ }
+
+ public void testOrderingInNestedOrs() {
+ OrPointcut opc = (OrPointcut) getPointcut("(execution(new(..)) || get(* *)) || within(abc)");
+ assertEquals("reordered","((within(abc) || get(* *)) || execution(new(..)))",
+ prw.rewrite(opc).toString());
+ }
+
+ public void testOrderingInOrsWithNestedAnds() {
+ OrPointcut opc = (OrPointcut) getPointcut("get(* *) || (execution(new(..)) && within(abc))");
+ assertEquals("reordered","((within(abc) && execution(new(..))) || get(* *))",
+ prw.rewrite(opc).toString());
+ }
+
+ private Pointcut getPointcut(String s) {
+ return new PatternParser(s).parsePointcut();
+ }
+
+ /*
+ * @see TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ prw = new PointcutRewriter();
+ }
+
+}
diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/PointcutTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/PointcutTestCase.java
index a640a07d5..039bf89d5 100644
--- a/weaver/testsrc/org/aspectj/weaver/patterns/PointcutTestCase.java
+++ b/weaver/testsrc/org/aspectj/weaver/patterns/PointcutTestCase.java
@@ -12,6 +12,7 @@ package org.aspectj.weaver.patterns;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
@@ -30,11 +31,15 @@ public class PointcutTestCase extends TestCase {
public void testMatchJP() {
Pointcut p = new Pointcut() {
+ public Set couldMatchKinds() {
+ return null;
+ }
+
public FuzzyBoolean fastMatch(FastMatchInfo info) {
return null;
}
- public FuzzyBoolean match(Shadow shadow) {
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
return null;
}
@@ -47,7 +52,7 @@ public class PointcutTestCase extends TestCase {
return null;
}
- public Test findResidue(Shadow shadow, ExposedState state) {
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
return null;
}