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.

IfPointcut.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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 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. * Contributors:
  10. * PARC initial implementation
  11. * Alexandre Vasseur if() implementation for @AJ style
  12. * ******************************************************************/
  13. package org.aspectj.weaver.patterns;
  14. import java.io.DataOutputStream;
  15. import java.io.IOException;
  16. import java.lang.reflect.Member;
  17. import java.util.ArrayList;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import java.util.Set;
  21. import org.aspectj.bridge.IMessage;
  22. import org.aspectj.lang.JoinPoint;
  23. import org.aspectj.util.FuzzyBoolean;
  24. import org.aspectj.weaver.Advice;
  25. import org.aspectj.weaver.ISourceContext;
  26. import org.aspectj.weaver.IntMap;
  27. import org.aspectj.weaver.ResolvedMember;
  28. import org.aspectj.weaver.ResolvedPointcutDefinition;
  29. import org.aspectj.weaver.ResolvedTypeX;
  30. import org.aspectj.weaver.Shadow;
  31. import org.aspectj.weaver.ShadowMunger;
  32. import org.aspectj.weaver.VersionedDataInputStream;
  33. import org.aspectj.weaver.WeaverMessages;
  34. import org.aspectj.weaver.TypeX;
  35. import org.aspectj.weaver.AjcMemberMaker;
  36. import org.aspectj.weaver.ast.Expr;
  37. import org.aspectj.weaver.ast.Literal;
  38. import org.aspectj.weaver.ast.Test;
  39. import org.aspectj.weaver.ast.Var;
  40. public class IfPointcut extends Pointcut {
  41. public ResolvedMember testMethod;
  42. public int extraParameterFlags;
  43. /**
  44. * A token source dump that looks like a pointcut (but is NOT parseable at all - just here to help debugging etc)
  45. */
  46. private String enclosingPointcutHint;
  47. public Pointcut residueSource;
  48. int baseArgsCount;
  49. //XXX some way to compute args
  50. public IfPointcut(ResolvedMember testMethod, int extraParameterFlags) {
  51. this.testMethod = testMethod;
  52. this.extraParameterFlags = extraParameterFlags;
  53. this.pointcutKind = IF;
  54. this.enclosingPointcutHint = null;
  55. }
  56. /**
  57. * No-arg constructor for @AJ style, where the if() body is actually the @Pointcut annotated method
  58. */
  59. public IfPointcut(String enclosingPointcutHint) {
  60. this.pointcutKind = IF;
  61. this.enclosingPointcutHint = enclosingPointcutHint;
  62. this.testMethod = null;// resolved during concretize
  63. this.extraParameterFlags = -1;//allows to keep track of the @Aj style
  64. }
  65. public Set couldMatchKinds() {
  66. return Shadow.ALL_SHADOW_KINDS;
  67. }
  68. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  69. return FuzzyBoolean.MAYBE;
  70. }
  71. public FuzzyBoolean fastMatch(Class targetType) {
  72. return FuzzyBoolean.MAYBE;
  73. }
  74. protected FuzzyBoolean matchInternal(Shadow shadow) {
  75. //??? this is not maximally efficient
  76. return FuzzyBoolean.MAYBE;
  77. }
  78. public boolean alwaysFalse() {
  79. return false;
  80. }
  81. public boolean alwaysTrue() {
  82. return false;
  83. }
  84. // enh 76055
  85. public Pointcut getResidueSource() {
  86. return residueSource;
  87. }
  88. /* (non-Javadoc)
  89. * @see org.aspectj.weaver.patterns.Pointcut#matchesDynamically(java.lang.Object, java.lang.Object, java.lang.Object[])
  90. */
  91. public boolean matchesDynamically(Object thisObject, Object targetObject,
  92. Object[] args) {
  93. throw new UnsupportedOperationException("If pointcut matching not supported by this operation");
  94. }
  95. /* (non-Javadoc)
  96. * @see org.aspectj.weaver.patterns.Pointcut#matchesStatically(java.lang.String, java.lang.reflect.Member, java.lang.Class, java.lang.Class, java.lang.reflect.Member)
  97. */
  98. public FuzzyBoolean matchesStatically(
  99. String joinpointKind, Member member, Class thisClass,
  100. Class targetClass, Member withinCode) {
  101. throw new UnsupportedOperationException("If pointcut matching not supported by this operation");
  102. }
  103. public void write(DataOutputStream s) throws IOException {
  104. s.writeByte(Pointcut.IF);
  105. testMethod.write(s);//TODO Adrian, do something if this one happens to be null for @style if() from JDT stuff
  106. s.writeByte(extraParameterFlags);
  107. writeLocation(s);
  108. }
  109. public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  110. //TODO Adrian, read may failt if testMethod happens to be null for @style if() from JDT stuff
  111. IfPointcut ret = new IfPointcut(ResolvedMember.readResolvedMember(s, context), s.readByte());
  112. ret.readLocation(context, s);
  113. return ret;
  114. }
  115. public void resolveBindings(IScope scope, Bindings bindings) {
  116. //??? all we need is good error messages in here in cflow contexts
  117. }
  118. public void resolveBindingsFromRTTI() {}
  119. public boolean equals(Object other) {
  120. if (!(other instanceof IfPointcut)) return false;
  121. IfPointcut o = (IfPointcut)other;
  122. return o.testMethod.equals(this.testMethod);
  123. }
  124. public int hashCode() {
  125. int result = 17;
  126. result = 37*result + testMethod.hashCode();
  127. return result;
  128. }
  129. public String toString() {
  130. if (extraParameterFlags < 0) {
  131. //@AJ style
  132. return "if()";
  133. } else {
  134. return "if(" + testMethod + ")";//FIXME AV - bad, this makes it unparsable. Perhaps we can use if() for code style behind the scene!
  135. }
  136. }
  137. //??? The implementation of name binding and type checking in if PCDs is very convoluted
  138. // There has to be a better way...
  139. private boolean findingResidue = false;
  140. // Similar to lastMatchedShadowId - but only for if PCDs.
  141. private int ifLastMatchedShadowId;
  142. private Test ifLastMatchedShadowResidue;
  143. /**
  144. * At each shadow that matched, the residue can be different.
  145. */
  146. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  147. if (findingResidue) return Literal.TRUE;
  148. findingResidue = true;
  149. try {
  150. // Have we already been asked this question?
  151. if (shadow.shadowId == ifLastMatchedShadowId) return ifLastMatchedShadowResidue;
  152. Test ret = Literal.TRUE;
  153. List args = new ArrayList();
  154. // code style
  155. if (extraParameterFlags >= 0) {
  156. // If there are no args to sort out, don't bother with the recursive call
  157. if (baseArgsCount > 0) {
  158. ExposedState myState = new ExposedState(baseArgsCount);
  159. //??? we throw out the test that comes from this walk. All we want here
  160. // is bindings for the arguments
  161. residueSource.findResidue(shadow, myState);
  162. for (int i=0; i < baseArgsCount; i++) {
  163. Var v = myState.get(i);
  164. args.add(v);
  165. ret = Test.makeAnd(ret,
  166. Test.makeInstanceof(v,
  167. testMethod.getParameterTypes()[i].resolve(shadow.getIWorld())));
  168. }
  169. }
  170. // handle thisJoinPoint parameters
  171. if ((extraParameterFlags & Advice.ThisJoinPoint) != 0) {
  172. args.add(shadow.getThisJoinPointVar());
  173. }
  174. if ((extraParameterFlags & Advice.ThisJoinPointStaticPart) != 0) {
  175. args.add(shadow.getThisJoinPointStaticPartVar());
  176. }
  177. if ((extraParameterFlags & Advice.ThisEnclosingJoinPointStaticPart) != 0) {
  178. args.add(shadow.getThisEnclosingJoinPointStaticPartVar());
  179. }
  180. } else {
  181. // @style is slightly different
  182. int currentStateIndex = 0;
  183. //FIXME AV - "args(jp)" test(jp, thejp) will fail here
  184. for (int i = 0; i < testMethod.getParameterTypes().length; i++) {
  185. String argSignature = testMethod.getParameterTypes()[i].getSignature();
  186. if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argSignature)) {
  187. args.add(shadow.getThisJoinPointVar());
  188. } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argSignature)) {
  189. args.add(shadow.getThisJoinPointVar());
  190. } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argSignature)) {
  191. args.add(shadow.getThisJoinPointStaticPartVar());
  192. } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argSignature)) {
  193. args.add(shadow.getThisEnclosingJoinPointStaticPartVar());
  194. } else {
  195. // we don't use i as JoinPoint.* can be anywhere in the signature in @style
  196. Var v = state.get(currentStateIndex++);
  197. args.add(v);
  198. ret = Test.makeAnd(ret,
  199. Test.makeInstanceof(v,
  200. testMethod.getParameterTypes()[i].resolve(shadow.getIWorld())));
  201. }
  202. }
  203. }
  204. ret = Test.makeAnd(ret, Test.makeCall(testMethod, (Expr[])args.toArray(new Expr[args.size()])));
  205. // Remember...
  206. ifLastMatchedShadowId = shadow.shadowId;
  207. ifLastMatchedShadowResidue = ret;
  208. return ret;
  209. } finally {
  210. findingResidue = false;
  211. }
  212. }
  213. // amc - the only reason this override seems to be here is to stop the copy, but
  214. // that can be prevented by overriding shouldCopyLocationForConcretization,
  215. // allowing me to make the method final in Pointcut.
  216. // public Pointcut concretize(ResolvedTypeX inAspect, IntMap bindings) {
  217. // return this.concretize1(inAspect, bindings);
  218. // }
  219. protected boolean shouldCopyLocationForConcretize() {
  220. return false;
  221. }
  222. private IfPointcut partiallyConcretized = null;
  223. public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
  224. //System.err.println("concretize: " + this + " already: " + partiallyConcretized);
  225. if (isDeclare(bindings.getEnclosingAdvice())) {
  226. // Enforce rule about which designators are supported in declare
  227. inAspect.getWorld().showMessage(IMessage.ERROR,
  228. WeaverMessages.format(WeaverMessages.IF_IN_DECLARE),
  229. bindings.getEnclosingAdvice().getSourceLocation(),
  230. null);
  231. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  232. }
  233. if (partiallyConcretized != null) {
  234. return partiallyConcretized;
  235. }
  236. final IfPointcut ret;
  237. if (extraParameterFlags < 0 && testMethod == null) {
  238. // @AJ style, we need to find the testMethod in the aspect defining the "if()" enclosing pointcut
  239. ResolvedPointcutDefinition def = bindings.peekEnclosingDefinitition();
  240. if (def != null) {
  241. ResolvedTypeX aspect = inAspect.getWorld().resolve(def.getDeclaringType());
  242. ResolvedMember[] methods = aspect.getDeclaredJavaMethods();
  243. for (int i = 0; i < methods.length; i++) {
  244. ResolvedMember method = methods[i];
  245. if (def.getName().equals(method.getName())
  246. && def.getParameterTypes().length == method.getParameterTypes().length) {
  247. boolean sameSig = true;
  248. for (int j = 0; j < method.getParameterTypes().length; j++) {
  249. TypeX argJ = method.getParameterTypes()[j];
  250. if (!argJ.equals(def.getParameterTypes()[j])) {
  251. sameSig = false;
  252. break;
  253. }
  254. }
  255. if (sameSig) {
  256. testMethod = method;
  257. break;
  258. }
  259. }
  260. }
  261. if (testMethod == null) {
  262. inAspect.getWorld().showMessage(
  263. IMessage.ERROR,
  264. "Cannot find if() body from '" + def.toString() + "' for '" + enclosingPointcutHint + "'",
  265. this.getSourceLocation(),
  266. null
  267. );
  268. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  269. }
  270. } else {
  271. testMethod = inAspect.getWorld().resolve(bindings.getAdviceSignature());
  272. }
  273. ret = new IfPointcut(enclosingPointcutHint);
  274. ret.testMethod = testMethod;
  275. } else {
  276. ret = new IfPointcut(testMethod, extraParameterFlags);
  277. }
  278. ret.copyLocationFrom(this);
  279. partiallyConcretized = ret;
  280. // It is possible to directly code your pointcut expression in a per clause
  281. // rather than defining a pointcut declaration and referencing it in your
  282. // per clause. If you do this, we have problems (bug #62458). For now,
  283. // let's police that you are trying to code a pointcut in a per clause and
  284. // put out a compiler error.
  285. if (bindings.directlyInAdvice() && bindings.getEnclosingAdvice()==null) {
  286. // Assumption: if() is in a per clause if we say we are directly in advice
  287. // but we have no enclosing advice.
  288. inAspect.getWorld().showMessage(IMessage.ERROR,
  289. WeaverMessages.format(WeaverMessages.IF_IN_PERCLAUSE),
  290. this.getSourceLocation(),null);
  291. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  292. }
  293. if (bindings.directlyInAdvice()) {
  294. ShadowMunger advice = bindings.getEnclosingAdvice();
  295. if (advice instanceof Advice) {
  296. ret.baseArgsCount = ((Advice)advice).getBaseParameterCount();
  297. } else {
  298. ret.baseArgsCount = 0;
  299. }
  300. ret.residueSource = advice.getPointcut().concretize(inAspect, ret.baseArgsCount, advice);
  301. } else {
  302. ResolvedPointcutDefinition def = bindings.peekEnclosingDefinitition();
  303. if (def == CflowPointcut.CFLOW_MARKER) {
  304. inAspect.getWorld().showMessage(IMessage.ERROR,
  305. WeaverMessages.format(WeaverMessages.IF_LEXICALLY_IN_CFLOW),
  306. getSourceLocation(), null);
  307. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  308. }
  309. ret.baseArgsCount = def.getParameterTypes().length;
  310. // for @style, we have implicit binding for JoinPoint.* things
  311. //FIXME AV - will lead to failure for "args(jp)" test(jp, thejp) / see args() implementation
  312. if (ret.extraParameterFlags < 0) {
  313. ret.baseArgsCount = 0;
  314. for (int i = 0; i < testMethod.getParameterTypes().length; i++) {
  315. String argSignature = testMethod.getParameterTypes()[i].getSignature();
  316. if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argSignature)
  317. || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argSignature)
  318. || AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argSignature)
  319. || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argSignature)) {
  320. ;
  321. } else {
  322. ret.baseArgsCount++;
  323. }
  324. }
  325. }
  326. IntMap newBindings = IntMap.idMap(ret.baseArgsCount);
  327. newBindings.copyContext(bindings);
  328. ret.residueSource = def.getPointcut().concretize(inAspect, newBindings);
  329. }
  330. return ret;
  331. }
  332. // public static Pointcut MatchesNothing = new MatchesNothingPointcut();
  333. // ??? there could possibly be some good optimizations to be done at this point
  334. public static IfPointcut makeIfFalsePointcut(State state) {
  335. IfPointcut ret = new IfFalsePointcut();
  336. ret.state = state;
  337. return ret;
  338. }
  339. public Object accept(PatternNodeVisitor visitor, Object data) {
  340. return visitor.visit(this, data);
  341. }
  342. public static class IfFalsePointcut extends IfPointcut {
  343. public IfFalsePointcut() {
  344. super(null,0);
  345. this.pointcutKind = Pointcut.IF_FALSE;
  346. }
  347. public Set couldMatchKinds() {
  348. return Collections.EMPTY_SET;
  349. }
  350. public boolean alwaysFalse() {
  351. return true;
  352. }
  353. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  354. return Literal.FALSE; // can only get here if an earlier error occurred
  355. }
  356. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  357. return FuzzyBoolean.NO;
  358. }
  359. protected FuzzyBoolean matchInternal(Shadow shadow) {
  360. return FuzzyBoolean.NO;
  361. }
  362. public FuzzyBoolean match(JoinPoint.StaticPart jpsp) {
  363. return FuzzyBoolean.NO;
  364. }
  365. public void resolveBindings(IScope scope, Bindings bindings) {
  366. }
  367. public void resolveBindingsFromRTTI() {
  368. }
  369. public void postRead(ResolvedTypeX enclosingType) {
  370. }
  371. public Pointcut concretize1(
  372. ResolvedTypeX inAspect,
  373. IntMap bindings) {
  374. if (isDeclare(bindings.getEnclosingAdvice())) {
  375. // Enforce rule about which designators are supported in declare
  376. inAspect.getWorld().showMessage(IMessage.ERROR,
  377. WeaverMessages.format(WeaverMessages.IF_IN_DECLARE),
  378. bindings.getEnclosingAdvice().getSourceLocation(),
  379. null);
  380. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  381. }
  382. return makeIfFalsePointcut(state);
  383. }
  384. public void write(DataOutputStream s) throws IOException {
  385. s.writeByte(Pointcut.IF_FALSE);
  386. }
  387. public int hashCode() {
  388. int result = 17;
  389. return result;
  390. }
  391. public String toString() {
  392. return "if(false)";
  393. }
  394. }
  395. public static IfPointcut makeIfTruePointcut(State state) {
  396. IfPointcut ret = new IfTruePointcut();
  397. ret.state = state;
  398. return ret;
  399. }
  400. public static class IfTruePointcut extends IfPointcut {
  401. public IfTruePointcut() {
  402. super(null,0);
  403. this.pointcutKind = Pointcut.IF_TRUE;
  404. }
  405. public boolean alwaysTrue() {
  406. return true;
  407. }
  408. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  409. return Literal.TRUE; // can only get here if an earlier error occurred
  410. }
  411. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  412. return FuzzyBoolean.YES;
  413. }
  414. protected FuzzyBoolean matchInternal(Shadow shadow) {
  415. return FuzzyBoolean.YES;
  416. }
  417. public FuzzyBoolean match(JoinPoint.StaticPart jpsp) {
  418. return FuzzyBoolean.YES;
  419. }
  420. public void resolveBindings(IScope scope, Bindings bindings) {
  421. }
  422. public void resolveBindingsFromRTTI() {
  423. }
  424. public void postRead(ResolvedTypeX enclosingType) {
  425. }
  426. public Pointcut concretize1(
  427. ResolvedTypeX inAspect,
  428. IntMap bindings) {
  429. if (isDeclare(bindings.getEnclosingAdvice())) {
  430. // Enforce rule about which designators are supported in declare
  431. inAspect.getWorld().showMessage(IMessage.ERROR,
  432. WeaverMessages.format(WeaverMessages.IF_IN_DECLARE),
  433. bindings.getEnclosingAdvice().getSourceLocation(),
  434. null);
  435. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  436. }
  437. return makeIfTruePointcut(state);
  438. }
  439. public void write(DataOutputStream s) throws IOException {
  440. s.writeByte(IF_TRUE);
  441. }
  442. public int hashCode() {
  443. int result = 37;
  444. return result;
  445. }
  446. public String toString() {
  447. return "if(true)";
  448. }
  449. }
  450. }