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.

ReferencePointcut.java 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. * ******************************************************************/
  12. package org.aspectj.weaver.patterns;
  13. import java.io.DataInputStream;
  14. import java.io.DataOutputStream;
  15. import java.io.IOException;
  16. import java.lang.reflect.Modifier;
  17. import java.util.Set;
  18. import org.aspectj.bridge.IMessage;
  19. import org.aspectj.bridge.MessageUtil;
  20. import org.aspectj.util.FuzzyBoolean;
  21. import org.aspectj.weaver.BCException;
  22. import org.aspectj.weaver.ISourceContext;
  23. import org.aspectj.weaver.IntMap;
  24. import org.aspectj.weaver.ResolvedPointcutDefinition;
  25. import org.aspectj.weaver.ResolvedTypeX;
  26. import org.aspectj.weaver.Shadow;
  27. import org.aspectj.weaver.ShadowMunger;
  28. import org.aspectj.weaver.TypeX;
  29. import org.aspectj.weaver.WeaverMessages;
  30. import org.aspectj.weaver.ast.Test;
  31. /**
  32. */
  33. //XXX needs check that arguments contains no WildTypePatterns
  34. public class ReferencePointcut extends Pointcut {
  35. public TypeX onType;
  36. public TypePattern onTypeSymbolic;
  37. public String name;
  38. public TypePatternList arguments;
  39. //public ResolvedPointcut binding;
  40. public ReferencePointcut(TypePattern onTypeSymbolic, String name, TypePatternList arguments) {
  41. this.onTypeSymbolic = onTypeSymbolic;
  42. this.name = name;
  43. this.arguments = arguments;
  44. this.pointcutKind = REFERENCE;
  45. }
  46. public ReferencePointcut(TypeX onType, String name, TypePatternList arguments) {
  47. this.onType = onType;
  48. this.name = name;
  49. this.arguments = arguments;
  50. this.pointcutKind = REFERENCE;
  51. }
  52. public Set couldMatchKinds() {
  53. return Shadow.ALL_SHADOW_KINDS;
  54. }
  55. //??? do either of these match methods make any sense???
  56. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  57. return FuzzyBoolean.MAYBE;
  58. }
  59. /**
  60. * Do I really match this shadow?
  61. */
  62. protected FuzzyBoolean matchInternal(Shadow shadow) {
  63. return FuzzyBoolean.NO;
  64. }
  65. public String toString() {
  66. StringBuffer buf = new StringBuffer();
  67. if (onType != null) {
  68. buf.append(onType);
  69. buf.append(".");
  70. // for (int i=0, len=fromType.length; i < len; i++) {
  71. // buf.append(fromType[i]);
  72. // buf.append(".");
  73. // }
  74. }
  75. buf.append(name);
  76. buf.append(arguments.toString());
  77. return buf.toString();
  78. }
  79. public void write(DataOutputStream s) throws IOException {
  80. //XXX ignores onType
  81. s.writeByte(Pointcut.REFERENCE);
  82. if (onType != null) {
  83. s.writeBoolean(true);
  84. onType.write(s);
  85. } else {
  86. s.writeBoolean(false);
  87. }
  88. s.writeUTF(name);
  89. arguments.write(s);
  90. writeLocation(s);
  91. }
  92. public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException {
  93. TypeX onType = null;
  94. if (s.readBoolean()) {
  95. onType = TypeX.read(s);
  96. }
  97. ReferencePointcut ret = new ReferencePointcut(onType, s.readUTF(),
  98. TypePatternList.read(s, context));
  99. ret.readLocation(context, s);
  100. return ret;
  101. }
  102. public void resolveBindings(IScope scope, Bindings bindings) {
  103. if (onTypeSymbolic != null) {
  104. onType = onTypeSymbolic.resolveExactType(scope, bindings);
  105. // in this case we've already signalled an error
  106. if (onType == ResolvedTypeX.MISSING) return;
  107. }
  108. ResolvedTypeX searchType;
  109. if (onType != null) {
  110. searchType = scope.getWorld().resolve(onType);
  111. } else {
  112. searchType = scope.getEnclosingType();
  113. }
  114. arguments.resolveBindings(scope, bindings, true, true);
  115. //XXX ensure that arguments has no ..'s in it
  116. // check that I refer to a real pointcut declaration and that I match
  117. ResolvedPointcutDefinition pointcutDef = searchType.findPointcut(name);
  118. // if we're not a static reference, then do a lookup of outers
  119. if (pointcutDef == null && onType == null) {
  120. while (true) {
  121. TypeX declaringType = searchType.getDeclaringType();
  122. if (declaringType == null) break;
  123. searchType = declaringType.resolve(scope.getWorld());
  124. pointcutDef = searchType.findPointcut(name);
  125. if (pointcutDef != null) {
  126. // make this a static reference
  127. onType = searchType;
  128. break;
  129. }
  130. }
  131. }
  132. if (pointcutDef == null) {
  133. scope.message(IMessage.ERROR, this, "can't find referenced pointcut");
  134. return;
  135. }
  136. // check visibility
  137. if (!pointcutDef.isVisible(scope.getEnclosingType())) {
  138. scope.message(IMessage.ERROR, this, "pointcut declaration " + pointcutDef + " is not accessible");
  139. return;
  140. }
  141. if (Modifier.isAbstract(pointcutDef.getModifiers())) {
  142. if (onType != null) {
  143. scope.message(IMessage.ERROR, this,
  144. "can't make static reference to abstract pointcut");
  145. return;
  146. } else if (!searchType.isAbstract()) {
  147. scope.message(IMessage.ERROR, this,
  148. "can't use abstract pointcut in concrete context");
  149. return;
  150. }
  151. }
  152. ResolvedTypeX[] parameterTypes =
  153. scope.getWorld().resolve(pointcutDef.getParameterTypes());
  154. if (parameterTypes.length != arguments.size()) {
  155. scope.message(IMessage.ERROR, this, "incompatible number of arguments to pointcut, expected " +
  156. parameterTypes.length + " found " + arguments.size());
  157. return;
  158. }
  159. for (int i=0,len=arguments.size(); i < len; i++) {
  160. TypePattern p = arguments.get(i);
  161. //we are allowed to bind to pointcuts which use subtypes as this is type safe
  162. if (p == TypePattern.NO) {
  163. scope.message(IMessage.ERROR, this,
  164. "bad parameter to pointcut reference");
  165. return;
  166. }
  167. if (!p.matchesSubtypes(parameterTypes[i]) &&
  168. !p.getExactType().equals(TypeX.OBJECT))
  169. {
  170. scope.message(IMessage.ERROR, p, "incompatible type, expected " +
  171. parameterTypes[i].getName() + " found " + p);
  172. return;
  173. }
  174. }
  175. }
  176. public void resolveBindingsFromRTTI() {
  177. throw new UnsupportedOperationException("Referenced pointcuts are not supported in runtime evaluation");
  178. }
  179. public void postRead(ResolvedTypeX enclosingType) {
  180. arguments.postRead(enclosingType);
  181. }
  182. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  183. throw new RuntimeException("shouldn't happen");
  184. }
  185. //??? This is not thread safe, but this class is not designed for multi-threading
  186. private boolean concretizing = false;
  187. public Pointcut concretize1(ResolvedTypeX searchStart, IntMap bindings) {
  188. if (concretizing) {
  189. //Thread.currentThread().dumpStack();
  190. searchStart.getWorld().getMessageHandler().handleMessage(
  191. MessageUtil.error(WeaverMessages.format(WeaverMessages.CIRCULAR_POINTCUT,this),
  192. getSourceLocation()));
  193. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  194. }
  195. try {
  196. concretizing = true;
  197. ResolvedPointcutDefinition pointcutDec;
  198. if (onType != null) {
  199. searchStart = onType.resolve(searchStart.getWorld());
  200. if (searchStart == ResolvedTypeX.MISSING) {
  201. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  202. }
  203. }
  204. pointcutDec = searchStart.findPointcut(name);
  205. if (pointcutDec == null) {
  206. searchStart.getWorld().getMessageHandler().handleMessage(
  207. MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_FIND_POINTCUT,name,searchStart.getName()),
  208. getSourceLocation())
  209. );
  210. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  211. }
  212. if (pointcutDec.isAbstract()) {
  213. //Thread.currentThread().dumpStack();
  214. ShadowMunger enclosingAdvice = bindings.getEnclosingAdvice();
  215. searchStart.getWorld().showMessage(IMessage.ERROR,
  216. WeaverMessages.format(WeaverMessages.ABSTRACT_POINTCUT,pointcutDec),
  217. getSourceLocation(),
  218. (null == enclosingAdvice) ? null : enclosingAdvice.getSourceLocation());
  219. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  220. }
  221. //System.err.println("start: " + searchStart);
  222. ResolvedTypeX[] parameterTypes = searchStart.getWorld().resolve(pointcutDec.getParameterTypes());
  223. TypePatternList arguments = this.arguments.resolveReferences(bindings);
  224. IntMap newBindings = new IntMap();
  225. for (int i=0,len=arguments.size(); i < len; i++) {
  226. TypePattern p = arguments.get(i);
  227. //we are allowed to bind to pointcuts which use subtypes as this is type safe
  228. if (!p.matchesSubtypes(parameterTypes[i]) &&
  229. !p.getExactType().equals(TypeX.OBJECT))
  230. {
  231. throw new BCException("illegal change to pointcut declaration: " + this);
  232. }
  233. if (p instanceof BindingTypePattern) {
  234. newBindings.put(i, ((BindingTypePattern)p).getFormalIndex());
  235. }
  236. }
  237. newBindings.copyContext(bindings);
  238. newBindings.pushEnclosingDefinition(pointcutDec);
  239. try {
  240. return pointcutDec.getPointcut().concretize(searchStart, newBindings);
  241. } finally {
  242. newBindings.popEnclosingDefinitition();
  243. }
  244. } finally {
  245. concretizing = false;
  246. }
  247. }
  248. // We want to keep the original source location, not the reference location
  249. protected boolean shouldCopyLocationForConcretize() {
  250. return false;
  251. }
  252. public boolean equals(Object other) {
  253. if (!(other instanceof ReferencePointcut)) return false;
  254. ReferencePointcut o = (ReferencePointcut)other;
  255. return o.name.equals(name) && o.arguments.equals(arguments)
  256. && ((o.onType == null) ? (onType == null) : o.onType.equals(onType));
  257. }
  258. public int hashCode() {
  259. int result = 17;
  260. result = 37*result + ((onType == null) ? 0 : onType.hashCode());
  261. result = 37*result + arguments.hashCode();
  262. result = 37*result + name.hashCode();
  263. return result;
  264. }
  265. }