You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Pointcut.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.patterns;
  13. import java.io.IOException;
  14. import java.util.Map;
  15. import org.aspectj.util.FuzzyBoolean;
  16. import org.aspectj.util.TypeSafeEnum;
  17. import org.aspectj.weaver.Advice;
  18. import org.aspectj.weaver.AdviceKind;
  19. import org.aspectj.weaver.BCException;
  20. import org.aspectj.weaver.Checker;
  21. import org.aspectj.weaver.CompressingDataOutputStream;
  22. import org.aspectj.weaver.ISourceContext;
  23. import org.aspectj.weaver.IntMap;
  24. import org.aspectj.weaver.PoliceExtensionUse;
  25. import org.aspectj.weaver.ResolvedType;
  26. import org.aspectj.weaver.Shadow;
  27. import org.aspectj.weaver.ShadowMunger;
  28. import org.aspectj.weaver.UnresolvedType;
  29. import org.aspectj.weaver.VersionedDataInputStream;
  30. import org.aspectj.weaver.World;
  31. import org.aspectj.weaver.ast.Literal;
  32. import org.aspectj.weaver.ast.Test;
  33. /**
  34. * The lifecycle of Pointcuts is modeled by Pointcut.State. It has three things:
  35. *
  36. * <p>
  37. * Creation -- SYMBOLIC -- then resolve(IScope) -- RESOLVED -- concretize(...) -- CONCRETE
  38. *
  39. * @author Erik Hilsdale
  40. * @author Jim Hugunin
  41. *
  42. * A day in the life of a pointcut.... - AMC. ==========================================
  43. *
  44. * Pointcuts are created by the PatternParser, which is called by ajdt to parse a pointcut from the PseudoTokens AST node
  45. * (which in turn are part of a PointcutDesignator AST node).
  46. *
  47. * Pointcuts are resolved by ajdt when an AdviceDeclaration or a PointcutDeclaration has its statements resolved. This
  48. * happens as part of completeTypeBindings in the AjLookupEnvironment which is called after the diet parse phase of the
  49. * compiler. Named pointcuts, and references to named pointcuts are instances of ReferencePointcut.
  50. *
  51. * At the end of the compilation process, the pointcuts are serialized (write method) into attributes in the class file.
  52. *
  53. * When the weaver loads the class files, it unpacks the attributes and deserializes the pointcuts (read). All aspects are
  54. * added to the world, by calling addOrReplaceAspect on the crosscutting members set of the world. When aspects are added or
  55. * replaced, the crosscutting members in the aspect are extracted as ShadowMungers (each holding a pointcut). The
  56. * ShadowMungers are concretized, which concretizes the pointcuts. At this stage ReferencePointcuts are replaced by their
  57. * declared content.
  58. *
  59. * During weaving, the weaver processes type by type. It first culls potentially matching ShadowMungers by calling the
  60. * fastMatch method on their pointcuts. Only those that might match make it through to the next phase. At the next phase,
  61. * all of the shadows within the type are created and passed to the pointcut for matching (match).
  62. *
  63. * When the actual munging happens, matched pointcuts are asked for their residue (findResidue) - the runtime test if any.
  64. * Because of negation, findResidue may be called on pointcuts that could never match the shadow.
  65. *
  66. */
  67. public abstract class Pointcut extends PatternNode {
  68. public static final class State extends TypeSafeEnum {
  69. public State(String name, int key) {
  70. super(name, key);
  71. }
  72. }
  73. /**
  74. * ATAJ the name of the formal for which we don't want any warning when unbound since we consider them as implicitly bound. f.e.
  75. * JoinPoint for @AJ advices
  76. */
  77. public String[] m_ignoreUnboundBindingForNames = EMPTY_STRING_ARRAY;
  78. public static final String[] EMPTY_STRING_ARRAY = new String[0];
  79. public static final State SYMBOLIC = new State("symbolic", 0);
  80. public static final State RESOLVED = new State("resolved", 1);
  81. public static final State CONCRETE = new State("concrete", 2);
  82. protected byte pointcutKind;
  83. public State state;
  84. protected int lastMatchedShadowId;
  85. private FuzzyBoolean lastMatchedShadowResult;
  86. private String[] typeVariablesInScope = EMPTY_STRING_ARRAY;
  87. protected boolean hasBeenParameterized = false;
  88. /**
  89. * Constructor for Pattern.
  90. */
  91. public Pointcut() {
  92. super();
  93. this.state = SYMBOLIC;
  94. }
  95. /**
  96. * Could I match any shadows in the code defined within this type?
  97. */
  98. public abstract FuzzyBoolean fastMatch(FastMatchInfo info);
  99. /**
  100. * The set of ShadowKinds that this Pointcut could possibly match - an int whose bits are set according to the Kinds specified
  101. * in Shadow.java
  102. */
  103. public abstract int couldMatchKinds();
  104. public String[] getTypeVariablesInScope() {
  105. return typeVariablesInScope;
  106. }
  107. public void setTypeVariablesInScope(String[] typeVars) {
  108. this.typeVariablesInScope = typeVars;
  109. }
  110. /**
  111. * Do I really match this shadow? XXX implementors need to handle state
  112. */
  113. public final FuzzyBoolean match(Shadow shadow) {
  114. if (shadow.shadowId == lastMatchedShadowId) {
  115. return lastMatchedShadowResult;
  116. }
  117. FuzzyBoolean ret;
  118. // this next test will prevent a lot of un-needed matching going on....
  119. if (shadow.getKind().isSet(couldMatchKinds())) {
  120. ret = matchInternal(shadow);
  121. } else {
  122. ret = FuzzyBoolean.NO;
  123. }
  124. lastMatchedShadowId = shadow.shadowId;
  125. lastMatchedShadowResult = ret;
  126. return ret;
  127. }
  128. protected abstract FuzzyBoolean matchInternal(Shadow shadow);
  129. public static final byte KINDED = 1;
  130. public static final byte WITHIN = 2;
  131. public static final byte THIS_OR_TARGET = 3;
  132. public static final byte ARGS = 4;
  133. public static final byte AND = 5;
  134. public static final byte OR = 6;
  135. public static final byte NOT = 7;
  136. public static final byte REFERENCE = 8;
  137. public static final byte IF = 9;
  138. public static final byte CFLOW = 10;
  139. public static final byte WITHINCODE = 12;
  140. public static final byte HANDLER = 13;
  141. public static final byte IF_TRUE = 14;
  142. public static final byte IF_FALSE = 15;
  143. public static final byte ANNOTATION = 16;
  144. public static final byte ATWITHIN = 17;
  145. public static final byte ATWITHINCODE = 18;
  146. public static final byte ATTHIS_OR_TARGET = 19;
  147. public static final byte NONE = 20; // DO NOT CHANGE OR REORDER THIS SEQUENCE, THIS VALUE CAN BE PUT OUT BY ASPECTJ1.2.1
  148. public static final byte ATARGS = 21;
  149. public static final byte USER_EXTENSION = 22;
  150. public byte getPointcutKind() {
  151. return pointcutKind;
  152. }
  153. // internal, only called from resolve
  154. protected abstract void resolveBindings(IScope scope, Bindings bindings);
  155. /**
  156. * Returns this pointcut mutated
  157. */
  158. public final Pointcut resolve(IScope scope) {
  159. assertState(SYMBOLIC);
  160. Bindings bindingTable = new Bindings(scope.getFormalCount());
  161. IScope bindingResolutionScope = scope;
  162. if (typeVariablesInScope.length > 0) {
  163. bindingResolutionScope = new ScopeWithTypeVariables(typeVariablesInScope, scope);
  164. }
  165. this.resolveBindings(bindingResolutionScope, bindingTable);
  166. bindingTable.checkAllBound(bindingResolutionScope);
  167. this.state = RESOLVED;
  168. return this;
  169. }
  170. /**
  171. * Returns a new pointcut Only used by test cases
  172. */
  173. public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, int arity) {
  174. Pointcut ret = concretize(inAspect, declaringType, IntMap.idMap(arity));
  175. // copy the unbound ignore list
  176. ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
  177. return ret;
  178. }
  179. // XXX this is the signature we're moving to
  180. public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, int arity, ShadowMunger advice) {
  181. // if (state == CONCRETE) return this; //???
  182. IntMap map = IntMap.idMap(arity);
  183. map.setEnclosingAdvice(advice);
  184. map.setConcreteAspect(inAspect);
  185. return concretize(inAspect, declaringType, map);
  186. }
  187. public boolean isDeclare(ShadowMunger munger) {
  188. if (munger == null) {
  189. return false; // ??? Is it actually an error if we get a null munger into this method.
  190. }
  191. if (munger instanceof Checker) {
  192. return true;
  193. }
  194. if (((Advice) munger).getKind().equals(AdviceKind.Softener)) {
  195. return true;
  196. }
  197. return false;
  198. }
  199. public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
  200. // !!! add this test -- assertState(RESOLVED);
  201. Pointcut ret = this.concretize1(inAspect, declaringType, bindings);
  202. if (shouldCopyLocationForConcretize()) {
  203. ret.copyLocationFrom(this);
  204. }
  205. ret.state = CONCRETE;
  206. // copy the unbound ignore list
  207. ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
  208. return ret;
  209. }
  210. protected boolean shouldCopyLocationForConcretize() {
  211. return true;
  212. }
  213. /**
  214. * Resolves and removes ReferencePointcuts, replacing with basic ones
  215. *
  216. * @param inAspect the aspect to resolve relative to
  217. * @param bindings a Map from formal index in the current lexical context &rarr; formal index in the concrete advice that will run
  218. *
  219. * This must always return a new Pointcut object (even if the concretized Pointcut is identical to the resolved one).
  220. * That behavior is assumed in many places. XXX fix implementors to handle state
  221. */
  222. protected abstract Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings);
  223. // XXX implementors need to handle state
  224. /**
  225. * This can be called from NotPointcut even for Pointcuts that don't match the shadow
  226. */
  227. public final Test findResidue(Shadow shadow, ExposedState state) {
  228. // if (shadow.shadowId == lastMatchedShadowId) return lastMatchedShadowResidue;
  229. Test ret = findResidueInternal(shadow, state);
  230. // lastMatchedShadowResidue = ret;
  231. lastMatchedShadowId = shadow.shadowId;
  232. return ret;
  233. }
  234. protected abstract Test findResidueInternal(Shadow shadow, ExposedState state);
  235. // XXX we're not sure whether or not this is needed
  236. // XXX currently it's unused we're keeping it around as a stub
  237. public void postRead(ResolvedType enclosingType) {
  238. }
  239. public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  240. byte kind = s.readByte();
  241. Pointcut ret;
  242. switch (kind) {
  243. case KINDED:
  244. ret = KindedPointcut.read(s, context);
  245. break;
  246. case WITHIN:
  247. ret = WithinPointcut.read(s, context);
  248. break;
  249. case THIS_OR_TARGET:
  250. ret = ThisOrTargetPointcut.read(s, context);
  251. break;
  252. case ARGS:
  253. ret = ArgsPointcut.read(s, context);
  254. break;
  255. case AND:
  256. ret = AndPointcut.read(s, context);
  257. break;
  258. case OR:
  259. ret = OrPointcut.read(s, context);
  260. break;
  261. case NOT:
  262. ret = NotPointcut.read(s, context);
  263. break;
  264. case REFERENCE:
  265. ret = ReferencePointcut.read(s, context);
  266. break;
  267. case IF:
  268. ret = IfPointcut.read(s, context);
  269. break;
  270. case CFLOW:
  271. ret = CflowPointcut.read(s, context);
  272. break;
  273. case WITHINCODE:
  274. ret = WithincodePointcut.read(s, context);
  275. break;
  276. case HANDLER:
  277. ret = HandlerPointcut.read(s, context);
  278. break;
  279. case IF_TRUE:
  280. ret = IfPointcut.makeIfTruePointcut(RESOLVED);
  281. break;
  282. case IF_FALSE:
  283. ret = IfPointcut.makeIfFalsePointcut(RESOLVED);
  284. break;
  285. case ANNOTATION:
  286. ret = AnnotationPointcut.read(s, context);
  287. break;
  288. case ATWITHIN:
  289. ret = WithinAnnotationPointcut.read(s, context);
  290. break;
  291. case ATWITHINCODE:
  292. ret = WithinCodeAnnotationPointcut.read(s, context);
  293. break;
  294. case ATTHIS_OR_TARGET:
  295. ret = ThisOrTargetAnnotationPointcut.read(s, context);
  296. break;
  297. case ATARGS:
  298. ret = ArgsAnnotationPointcut.read(s, context);
  299. break;
  300. case NONE:
  301. ret = makeMatchesNothing(RESOLVED);
  302. break;
  303. default:
  304. throw new BCException("unknown kind: " + kind);
  305. }
  306. ret.state = RESOLVED;
  307. ret.pointcutKind = kind;
  308. return ret;
  309. }
  310. public void check(ISourceContext ctx, World world) {
  311. // this is a quick visitor...
  312. PoliceExtensionUse pointcutPolice = new PoliceExtensionUse(world, this);
  313. this.accept(pointcutPolice, null);
  314. if (pointcutPolice.synchronizationDesignatorEncountered()) {
  315. world.setSynchronizationPointcutsInUse();
  316. }
  317. }
  318. // public void prepare(Shadow shadow) {}
  319. // ---- test method
  320. public static Pointcut fromString(String str) {
  321. PatternParser parser = new PatternParser(str);
  322. return parser.parsePointcut();
  323. }
  324. static class MatchesNothingPointcut extends Pointcut {
  325. @Override
  326. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  327. return Literal.FALSE; // can only get here if an earlier error occurred
  328. }
  329. @Override
  330. public int couldMatchKinds() {
  331. return Shadow.NO_SHADOW_KINDS_BITS;
  332. }
  333. @Override
  334. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  335. return FuzzyBoolean.NO;
  336. }
  337. @Override
  338. protected FuzzyBoolean matchInternal(Shadow shadow) {
  339. return FuzzyBoolean.NO;
  340. }
  341. @Override
  342. public void resolveBindings(IScope scope, Bindings bindings) {
  343. }
  344. @Override
  345. public void postRead(ResolvedType enclosingType) {
  346. }
  347. @Override
  348. public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
  349. return makeMatchesNothing(state);
  350. }
  351. @Override
  352. public void write(CompressingDataOutputStream s) throws IOException {
  353. s.writeByte(NONE);
  354. }
  355. @Override
  356. public String toString() {
  357. return "";
  358. }
  359. @Override
  360. public Object accept(PatternNodeVisitor visitor, Object data) {
  361. return visitor.visit(this, data);
  362. }
  363. @Override
  364. public Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
  365. return this;
  366. }
  367. }
  368. // public static Pointcut MatchesNothing = new MatchesNothingPointcut();
  369. // ??? there could possibly be some good optimizations to be done at this point
  370. public static Pointcut makeMatchesNothing(State state) {
  371. Pointcut ret = new MatchesNothingPointcut();
  372. ret.state = state;
  373. return ret;
  374. }
  375. public void assertState(State state) {
  376. if (this.state != state) {
  377. throw new BCException("expected state: " + state + " got: " + this.state);
  378. }
  379. }
  380. public abstract Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w);
  381. }