Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

PointcutRewriter.java 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /* *******************************************************************
  2. * Copyright (c) 2004 IBM Corporation.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * ******************************************************************/
  10. package org.aspectj.weaver.patterns;
  11. import java.util.Iterator;
  12. import java.util.Set;
  13. import java.util.SortedSet;
  14. import java.util.TreeSet;
  15. import org.aspectj.weaver.Shadow;
  16. /**
  17. * @author colyer
  18. *
  19. * Performs term rewriting for pointcut expressions.
  20. *
  21. */
  22. public class PointcutRewriter {
  23. private static final boolean WATCH_PROGRESS = false;
  24. public Pointcut rewrite(Pointcut pc) {
  25. if (WATCH_PROGRESS) System.out.println(pc);
  26. Pointcut result = distributeNot(pc);
  27. if (WATCH_PROGRESS) System.out.println("==> " + result);
  28. result = pullUpDisjunctions(result);
  29. if (WATCH_PROGRESS) System.out.println("==> " + result);
  30. result = simplifyAnds(result);
  31. if (WATCH_PROGRESS) System.out.println("==> " + result);
  32. result = sortOrs(result);
  33. if (WATCH_PROGRESS) System.out.println("==> " + result);
  34. return result;
  35. }
  36. // !!X => X
  37. // !(X && Y) => !X || !Y
  38. // !(X || Y) => !X && !Y
  39. private Pointcut distributeNot(Pointcut pc) {
  40. if (isNot(pc)) {
  41. NotPointcut npc = (NotPointcut) pc;
  42. Pointcut notBody = distributeNot(npc.getNegatedPointcut());
  43. if (isNot(notBody)) {
  44. // !!X => X
  45. return ((NotPointcut)notBody).getNegatedPointcut();
  46. } else if (isAnd(notBody)) {
  47. // !(X && Y) => !X || !Y
  48. AndPointcut apc = (AndPointcut) notBody;
  49. Pointcut newLeft = distributeNot(new NotPointcut(apc.getLeft()));
  50. Pointcut newRight = distributeNot(new NotPointcut(apc.getRight()));
  51. return new OrPointcut(newLeft,newRight);
  52. } else if (isOr(notBody)) {
  53. // !(X || Y) => !X && !Y
  54. OrPointcut opc = (OrPointcut) notBody;
  55. Pointcut newLeft = distributeNot(new NotPointcut(opc.getLeft()));
  56. Pointcut newRight = distributeNot(new NotPointcut(opc.getRight()));
  57. return new AndPointcut(newLeft,newRight);
  58. } else {
  59. return new NotPointcut(notBody);
  60. }
  61. } else if (isAnd(pc)) {
  62. AndPointcut apc = (AndPointcut) pc;
  63. Pointcut left = distributeNot(apc.getLeft());
  64. Pointcut right = distributeNot(apc.getRight());
  65. return new AndPointcut(left,right);
  66. } else if (isOr(pc)) {
  67. OrPointcut opc = (OrPointcut) pc;
  68. Pointcut left = distributeNot(opc.getLeft());
  69. Pointcut right = distributeNot(opc.getRight());
  70. return new OrPointcut(left,right);
  71. } else {
  72. return pc;
  73. }
  74. }
  75. // A && (B || C) => (A && B) || (A && C)
  76. // (A || B) && C => (A && C) || (B && C)
  77. private Pointcut pullUpDisjunctions(Pointcut pc) {
  78. if (isNot(pc)) {
  79. NotPointcut npc = (NotPointcut)pc;
  80. return new NotPointcut(pullUpDisjunctions(npc.getNegatedPointcut()));
  81. } else if (isAnd(pc)) {
  82. AndPointcut apc = (AndPointcut) pc;
  83. // dive into left and right here...
  84. Pointcut left = pullUpDisjunctions(apc.getLeft());
  85. Pointcut right = pullUpDisjunctions(apc.getRight());
  86. if (isOr(left) && !isOr(right)) {
  87. // (A || B) && C => (A && C) || (B && C)
  88. Pointcut leftLeft = ((OrPointcut)left).getLeft();
  89. Pointcut leftRight = ((OrPointcut)left).getRight();
  90. return new OrPointcut(
  91. new AndPointcut(leftLeft,right),
  92. new AndPointcut(leftRight,right));
  93. } else if (isOr(right) && !isOr(left)) {
  94. // A && (B || C) => (A && B) || (A && C)
  95. Pointcut rightLeft = ((OrPointcut)right).getLeft();
  96. Pointcut rightRight = ((OrPointcut)right).getRight();
  97. return new OrPointcut(
  98. new AndPointcut(left,rightLeft),
  99. new AndPointcut(left,rightRight));
  100. } else {
  101. return new AndPointcut(left,right);
  102. }
  103. } else if (isOr(pc)){
  104. OrPointcut opc = (OrPointcut) pc;
  105. return new OrPointcut(pullUpDisjunctions(opc.getLeft()),
  106. pullUpDisjunctions(opc.getRight()));
  107. } else {
  108. return pc;
  109. }
  110. }
  111. // NOT: execution(* TP.*(..)) => within(TP) && execution(* *(..))
  112. // since this breaks when the pattern matches an interface
  113. // NOT: withincode(* TP.*(..)) => within(TP) && withincode(* *(..))
  114. // since this is not correct when an aspect makes an ITD
  115. // private Pointcut splitOutWithins(Pointcut pc) {
  116. // if (isExecution(pc)) {
  117. // KindedPointcut kpc = (KindedPointcut) pc;
  118. // SignaturePattern sp = kpc.signature;
  119. // TypePattern within = sp.getDeclaringType();
  120. // if (isAnyType(within)) return pc;
  121. // SignaturePattern simplified = removeDeclaringTypePattern(sp);
  122. // return new AndPointcut(new WithinPointcut(within),
  123. // new KindedPointcut(kpc.kind,simplified));
  124. // } else if (isNot(pc)) {
  125. // return new NotPointcut(splitOutWithins(((NotPointcut)pc).getNegatedPointcut()));
  126. // } else if (isAnd(pc)) {
  127. // AndPointcut apc = (AndPointcut) pc;
  128. // return new AndPointcut(splitOutWithins(apc.getLeft()),
  129. // splitOutWithins(apc.getRight()));
  130. // } else if (isOr(pc)) {
  131. // OrPointcut opc = (OrPointcut) pc;
  132. // return new OrPointcut(splitOutWithins(opc.getLeft()),
  133. // splitOutWithins(opc.getRight()));
  134. // } else {
  135. // return pc;
  136. // }
  137. // }
  138. private SignaturePattern removeDeclaringTypePattern(SignaturePattern sp) {
  139. return new SignaturePattern(
  140. sp.getKind(),
  141. sp.getModifiers(),
  142. sp.getReturnType(),
  143. TypePattern.ANY,
  144. sp.getName(),
  145. sp.getParameterTypes(),
  146. sp.getThrowsPattern(),
  147. sp.getAnnotationPattern()
  148. );
  149. }
  150. // this finds the root of each && tree and then aggregates all of the branches
  151. // into a sorted set:
  152. // - duplicates are removed
  153. // - A && !A is replaced by a matchesNothingPointcut
  154. // - the kind(s) matched by the set are evaluated
  155. // - elements are sorted by evaluation complexity
  156. // - the result is written out with the least expensive branch leftmost
  157. private Pointcut simplifyAnds(Pointcut pc) {
  158. if (isNot(pc)) {
  159. NotPointcut npc = (NotPointcut) pc;
  160. return new NotPointcut(simplifyAnds(npc.getNegatedPointcut()));
  161. } else if (isOr(pc)) {
  162. OrPointcut opc = (OrPointcut) pc;
  163. return new OrPointcut(simplifyAnds(opc.getLeft()),simplifyAnds(opc.getRight()));
  164. } else if (isAnd(pc)) {
  165. return simplifyAnd((AndPointcut)pc);
  166. } else {
  167. return pc;
  168. }
  169. }
  170. private Pointcut simplifyAnd(AndPointcut apc) {
  171. SortedSet nodes = new TreeSet(new PointcutEvaluationExpenseComparator());
  172. collectAndNodes(apc,nodes);
  173. // look for A and !A, or IfFalse
  174. for (Iterator iter = nodes.iterator(); iter.hasNext();) {
  175. Pointcut element = (Pointcut) iter.next();
  176. if (element instanceof NotPointcut) {
  177. Pointcut body = ((NotPointcut)element).getNegatedPointcut();
  178. if (nodes.contains(body)) return Pointcut.makeMatchesNothing(body.state);
  179. }
  180. if (element instanceof IfPointcut) {
  181. if (((IfPointcut)element).alwaysFalse()) return Pointcut.makeMatchesNothing(element.state);
  182. }
  183. if (element.toString().equals("")) return element; // matches nothing...
  184. }
  185. if (apc.couldMatchKinds().isEmpty()) return Pointcut.makeMatchesNothing(apc.state);
  186. // write out with cheapest on left
  187. Iterator iter = nodes.iterator();
  188. Pointcut result = (Pointcut) iter.next();
  189. while(iter.hasNext()) {
  190. Pointcut right = (Pointcut) iter.next();
  191. result = new AndPointcut(result,right);
  192. }
  193. return result;
  194. }
  195. private Pointcut sortOrs(Pointcut pc) {
  196. SortedSet nodes = new TreeSet(new PointcutEvaluationExpenseComparator());
  197. collectOrNodes(pc,nodes);
  198. // write out with cheapest on left
  199. Iterator iter = nodes.iterator();
  200. Pointcut result = (Pointcut) iter.next();
  201. while(iter.hasNext()) {
  202. Pointcut right = (Pointcut) iter.next();
  203. result = new OrPointcut(result,right);
  204. }
  205. return result;
  206. }
  207. private void collectAndNodes(AndPointcut apc,Set nodesSoFar) {
  208. Pointcut left = apc.getLeft();
  209. Pointcut right = apc.getRight();
  210. if (isAnd(left)) {
  211. collectAndNodes((AndPointcut)left,nodesSoFar);
  212. } else {
  213. nodesSoFar.add(left);
  214. }
  215. if (isAnd(right)) {
  216. collectAndNodes((AndPointcut)right,nodesSoFar);
  217. } else {
  218. nodesSoFar.add(right);
  219. }
  220. }
  221. private void collectOrNodes(Pointcut pc, Set nodesSoFar) {
  222. if (isOr(pc)) {
  223. OrPointcut opc = (OrPointcut) pc;
  224. collectOrNodes(opc.getLeft(),nodesSoFar);
  225. collectOrNodes(opc.getRight(),nodesSoFar);
  226. } else {
  227. nodesSoFar.add(pc);
  228. }
  229. }
  230. private boolean isNot(Pointcut pc) {
  231. return (pc instanceof NotPointcut);
  232. }
  233. private boolean isAnd(Pointcut pc) {
  234. return (pc instanceof AndPointcut);
  235. }
  236. private boolean isOr(Pointcut pc) {
  237. return (pc instanceof OrPointcut);
  238. }
  239. private boolean isExecution(Pointcut pc) {
  240. if (pc instanceof KindedPointcut) {
  241. KindedPointcut kp = (KindedPointcut) pc;
  242. if (kp.kind == Shadow.MethodExecution) return true;
  243. if (kp.kind == Shadow.ConstructorExecution) return true;
  244. }
  245. return false;
  246. }
  247. private boolean isWithinCode(Pointcut pc) {
  248. return (pc instanceof WithincodePointcut);
  249. }
  250. private boolean isAnyType(TypePattern tp) {
  251. if (tp == TypePattern.ANY) return true;
  252. if (tp.toString().equals("*")) return true;
  253. return false;
  254. }
  255. }