123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- /* *******************************************************************
- * Copyright (c) 2004 IBM Corporation.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-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;
- import org.aspectj.weaver.patterns.Pointcut.MatchesNothingPointcut;
-
- /**
- * Performs term rewriting for pointcut expressions.
- *
- * @author colyer
- * @author clement
- */
- public class PointcutRewriter {
-
- private static final boolean WATCH_PROGRESS = false;
-
- /**
- * Set forcerewrite if you want to override the checking for something already in DNF (useful for some testing) Repeated
- * processing of something already in DNF is expensive (it ends up being done for every pointcut on every incremental compile) -
- * so let's not do it if we don't have to. See pr113257
- */
- public Pointcut rewrite(Pointcut pc, boolean forceRewrite) {
- Pointcut result = pc;// checkPC(result);
- if (forceRewrite || !isDNF(pc)) {
- if (WATCH_PROGRESS) {
- System.out.println("Initial pointcut is ==> " + format(pc));
- }
- result = distributeNot(result);// checkPC(result);
- if (WATCH_PROGRESS) {
- System.out.println("Distributing NOT gives ==> " + format(result));
- }
- result = pullUpDisjunctions(result);// checkPC(result);
- if (WATCH_PROGRESS) {
- System.out.println("Pull up disjunctions gives ==> " + format(result));
- }
- } else {
- if (WATCH_PROGRESS) {
- System.out.println("Not distributing NOTs or pulling up disjunctions, already DNF ==> " + format(pc));
- }
- }
- result = simplifyAnds(result); // checkPC(result);
- if (WATCH_PROGRESS) {
- System.out.println("Simplifying ANDs gives ==> " + format(result));
- }
- result = removeNothings(result); // checkPC(result);
- if (WATCH_PROGRESS) {
- System.out.println("Removing nothings gives ==> " + format(result));
- }
- result = sortOrs(result); // checkPC(result);
- if (WATCH_PROGRESS) {
- System.out.println("Sorting ORs gives ==> " + format(result));
- }
- return result;
- }
-
- // /**
- // * Checks pointcuts - used for debugging.
- // * - this variant checks if the context has been lost, since
- // * that can indicate an NPE will happen later reporting a message (pr162657).
- // * Not finished, but helped locate the problem ;)
- // */
- // private void checkPC(Pointcut pc) {
- // if (isNot(pc)) {
- // NotPointcut npc = (NotPointcut)pc;
- // checkPC(npc.getNegatedPointcut());
- // if (npc.getSourceContext()==null) {
- // System.out.println("Lost context for "+npc);
- // throw new RuntimeException("Lost context");
- // }
- // } else if (isOr(pc)) {
- // OrPointcut opc = (OrPointcut)pc;
- // checkPC(opc.getLeft());
- // checkPC(opc.getRight());
- // if (opc.getSourceContext()==null) {
- // System.out.println("Lost context for "+opc);
- // throw new RuntimeException("Lost context");
- // }
- // } else if (isAnd(pc)) {
- // AndPointcut apc = (AndPointcut)pc;
- // checkPC(apc.getLeft());
- // checkPC(apc.getRight());
- // if (apc.getSourceContext()==null) {
- // System.out.println("Lost context for "+apc);
- // throw new RuntimeException("Lost context");
- // }
- // } else {
- // if (pc.getSourceContext()==null) {
- // System.out.println("Lost context for "+pc);
- // throw new RuntimeException("Lost context");
- // }
- // }
- // }
-
- public Pointcut rewrite(Pointcut pc) {
- return rewrite(pc, false);
- }
-
- /**
- * Check if a pointcut is in DNF - if it is then it should be lots of 'ORs' up the top with 'ANDs' beneath them.
- */
- private boolean isDNF(Pointcut pc) {
- return isDNFHelper(pc, true);
- }
-
- /**
- * Helper function for determining DNFness. Records when we have crossed the point of allowing ORs.
- */
- private boolean isDNFHelper(Pointcut pc, boolean canStillHaveOrs) {
- if (isAnd(pc)) {
- AndPointcut ap = (AndPointcut) pc;
- return isDNFHelper(ap.getLeft(), false) && isDNFHelper(ap.getRight(), false);
- } else if (isOr(pc)) {
- if (!canStillHaveOrs) {
- return false;
- }
- OrPointcut op = (OrPointcut) pc;
- return isDNFHelper(op.getLeft(), true) && isDNFHelper(op.getRight(), true);
- } else if (isNot(pc)) {
- return isDNFHelper(((NotPointcut) pc).getNegatedPointcut(), canStillHaveOrs);
- } else {
- return true;
- }
- }
-
- /**
- * Allows formatting of the output pointcut for debugging...
- */
- public static String format(Pointcut p) {
- String s = p.toString();
- // Regex param needs '(' and '*' changing to '.'
- // s = s.replaceAll("persingleton.pkg1.monitoring.ErrorMonitoring.","M");
- // s = s.replaceAll("args.BindingTypePattern.java.lang.Throwable, 0.","Z");
- // s = s.replaceAll("within.pkg1.monitoring.DoMonitorErrors+.","X");
- // s=s.replaceAll("within.pkg1.monitoring....","Y");
- // s=s.replaceAll("if.true.","N");
- return s;
- }
-
- // !!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(), npc.getStart()));
- Pointcut newRight = distributeNot(new NotPointcut(apc.getRight(), npc.getStart()));
- return new OrPointcut(newLeft, newRight);
- } else if (isOr(notBody)) {
- // !(X || Y) => !X && !Y
- OrPointcut opc = (OrPointcut) notBody;
- Pointcut newLeft = distributeNot(new NotPointcut(opc.getLeft(), npc.getStart()));
- Pointcut newRight = distributeNot(new NotPointcut(opc.getRight(), npc.getStart()));
- return new AndPointcut(newLeft, newRight);
- } else {
- return new NotPointcut(notBody, npc.getStart());
- }
- } 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 pullUpDisjunctions(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 pullUpDisjunctions(new OrPointcut(new AndPointcut(left, rightLeft), new AndPointcut(left, rightRight)));
- } else if (isOr(right) && isOr(left)) {
- // (A || B) && (C || D) => (A && C) || (A && D) || (B && C) || (B && D)
- Pointcut A = pullUpDisjunctions(((OrPointcut) left).getLeft());
- Pointcut B = pullUpDisjunctions(((OrPointcut) left).getRight());
- Pointcut C = pullUpDisjunctions(((OrPointcut) right).getLeft());
- Pointcut D = pullUpDisjunctions(((OrPointcut) right).getRight());
- Pointcut newLeft = new OrPointcut(new AndPointcut(A, C), new AndPointcut(A, D));
- Pointcut newRight = new OrPointcut(new AndPointcut(B, C), new AndPointcut(B, D));
- return pullUpDisjunctions(new OrPointcut(newLeft, newRight));
- } 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;
- }
- }
-
- /**
- * Returns a NOTted form of the pointcut p - we cope with already NOTted pointcuts.
- */
- public Pointcut not(Pointcut p) {
- if (isNot(p)) {
- return ((NotPointcut) p).getNegatedPointcut();
- }
- return new NotPointcut(p);
- }
-
- /**
- * Passed an array of pointcuts, returns an AND tree with them in.
- */
- public Pointcut createAndsFor(Pointcut[] ps) {
- if (ps.length == 1) {
- return ps[0]; // dumb case
- }
- if (ps.length == 2) { // recursion exit case
- return new AndPointcut(ps[0], ps[1]);
- }
- // otherwise ...
- Pointcut[] subset = new Pointcut[ps.length - 1];
- for (int i = 1; i < ps.length; i++) {
- subset[i - 1] = ps[i];
- }
- return new AndPointcut(ps[0], createAndsFor(subset));
- }
-
- // 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;
- Pointcut notBody = npc.getNegatedPointcut();
- if (isNot(notBody)) {
- // !!X => X
- return simplifyAnds(((NotPointcut) notBody).getNegatedPointcut());
- } else {
- 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<Pointcut> nodes = new TreeSet<Pointcut>(new PointcutEvaluationExpenseComparator());
- collectAndNodes(apc, nodes);
- // look for A and !A, or IfFalse
- for (Iterator<Pointcut> iter = nodes.iterator(); iter.hasNext();) {
- Pointcut element = 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 it can't match anything, the whole AND can't match anything
- if (element.couldMatchKinds() == Shadow.NO_SHADOW_KINDS_BITS) {
- return element;
- }
- }
- if (apc.couldMatchKinds() == Shadow.NO_SHADOW_KINDS_BITS) {
- return Pointcut.makeMatchesNothing(apc.state);
- }
- // write out with cheapest on left
- Iterator<Pointcut> iter = nodes.iterator();
- Pointcut result = iter.next();
- while (iter.hasNext()) {
- Pointcut right = iter.next();
- result = new AndPointcut(result, right);
- }
- return result;
- }
-
- private Pointcut sortOrs(Pointcut pc) {
- SortedSet<Pointcut> nodes = new TreeSet<Pointcut>(new PointcutEvaluationExpenseComparator());
- collectOrNodes(pc, nodes);
- // write out with cheapest on left
- Iterator<Pointcut> iter = nodes.iterator();
- Pointcut result = iter.next();
- while (iter.hasNext()) {
- Pointcut right = iter.next();
- result = new OrPointcut(result, right);
- }
- return result;
- }
-
- /**
- * Removes MATCHES_NOTHING pointcuts
- */
- private Pointcut removeNothings(Pointcut pc) {
- if (isAnd(pc)) {
- AndPointcut apc = (AndPointcut) pc;
- Pointcut right = removeNothings(apc.getRight());
- Pointcut left = removeNothings(apc.getLeft());
- if (left instanceof MatchesNothingPointcut || right instanceof MatchesNothingPointcut) {
- return new MatchesNothingPointcut();
- }
- return new AndPointcut(left, right);
- } else if (isOr(pc)) {
- OrPointcut opc = (OrPointcut) pc;
- Pointcut right = removeNothings(opc.getRight());
- Pointcut left = removeNothings(opc.getLeft());
- if (left instanceof MatchesNothingPointcut && !(right instanceof MatchesNothingPointcut)) {
- return right;
- } else if (right instanceof MatchesNothingPointcut && !(left instanceof MatchesNothingPointcut)) {
- return left;
- } else if (!(left instanceof MatchesNothingPointcut) && !(right instanceof MatchesNothingPointcut)) {
- return new OrPointcut(left, right);
- } else if (left instanceof MatchesNothingPointcut && right instanceof MatchesNothingPointcut) {
- return new MatchesNothingPointcut();
- }
- }
- return pc;
- }
-
- private void collectAndNodes(AndPointcut apc, Set<Pointcut> 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<Pointcut> 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);
- }
-
- }
|