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.

SignaturePattern.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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.Field;
  17. import java.lang.reflect.Method;
  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import org.aspectj.lang.JoinPoint;
  23. import org.aspectj.lang.Signature;
  24. import org.aspectj.lang.reflect.AdviceSignature;
  25. import org.aspectj.lang.reflect.ConstructorSignature;
  26. import org.aspectj.lang.reflect.FieldSignature;
  27. import org.aspectj.lang.reflect.MethodSignature;
  28. import org.aspectj.weaver.ISourceContext;
  29. import org.aspectj.weaver.Member;
  30. import org.aspectj.weaver.NameMangler;
  31. import org.aspectj.weaver.ResolvedMember;
  32. import org.aspectj.weaver.ResolvedTypeX;
  33. import org.aspectj.weaver.TypeX;
  34. import org.aspectj.weaver.World;
  35. public class SignaturePattern extends PatternNode {
  36. private Member.Kind kind;
  37. private ModifiersPattern modifiers;
  38. private TypePattern returnType;
  39. private TypePattern declaringType;
  40. private NamePattern name;
  41. private TypePatternList parameterTypes;
  42. private ThrowsPattern throwsPattern;
  43. public SignaturePattern(Member.Kind kind, ModifiersPattern modifiers,
  44. TypePattern returnType, TypePattern declaringType,
  45. NamePattern name, TypePatternList parameterTypes,
  46. ThrowsPattern throwsPattern) {
  47. this.kind = kind;
  48. this.modifiers = modifiers;
  49. this.returnType = returnType;
  50. this.name = name;
  51. this.declaringType = declaringType;
  52. this.parameterTypes = parameterTypes;
  53. this.throwsPattern = throwsPattern;
  54. }
  55. public SignaturePattern resolveBindings(IScope scope, Bindings bindings) {
  56. if (returnType != null) {
  57. returnType = returnType.resolveBindings(scope, bindings, false, false);
  58. }
  59. if (declaringType != null) {
  60. declaringType = declaringType.resolveBindings(scope, bindings, false, false);
  61. }
  62. if (parameterTypes != null) {
  63. parameterTypes = parameterTypes.resolveBindings(scope, bindings, false, false);
  64. }
  65. if (throwsPattern != null) {
  66. throwsPattern = throwsPattern.resolveBindings(scope, bindings);
  67. }
  68. return this;
  69. }
  70. public SignaturePattern resolveBindingsFromRTTI() {
  71. if (returnType != null) {
  72. returnType = returnType.resolveBindingsFromRTTI(false, false);
  73. }
  74. if (declaringType != null) {
  75. declaringType = declaringType.resolveBindingsFromRTTI(false, false);
  76. }
  77. if (parameterTypes != null) {
  78. parameterTypes = parameterTypes.resolveBindingsFromRTTI(false, false);
  79. }
  80. if (throwsPattern != null) {
  81. throwsPattern = throwsPattern.resolveBindingsFromRTTI();
  82. }
  83. return this;
  84. }
  85. public void postRead(ResolvedTypeX enclosingType) {
  86. if (returnType != null) {
  87. returnType.postRead(enclosingType);
  88. }
  89. if (declaringType != null) {
  90. declaringType.postRead(enclosingType);
  91. }
  92. if (parameterTypes != null) {
  93. parameterTypes.postRead(enclosingType);
  94. }
  95. }
  96. public boolean matches(Member member, World world) {
  97. //XXX performance gains would come from matching on name before resolving
  98. // to fail fast. ASC 30th Nov 04 => Not necessarily, it didn't make it faster for me.
  99. // Here is the code I used:
  100. // String n1 = member.getName();
  101. // String n2 = this.getName().maybeGetSimpleName();
  102. // if (n2!=null && !n1.equals(n2)) return false;
  103. ResolvedMember sig = member.resolve(world);
  104. // Java5 introduces bridge methods, we don't want to match on them at all...
  105. if (sig.isBridgeMethod()) {
  106. return false;
  107. }
  108. if (sig == null) {
  109. //XXX
  110. if (member.getName().startsWith(NameMangler.PREFIX)) {
  111. return false;
  112. }
  113. world.getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
  114. return false;
  115. }
  116. // This check should only matter when used from WithincodePointcut as KindedPointcut
  117. // has already effectively checked this with the shadows kind.
  118. if (kind != member.getKind()) {
  119. return false;
  120. }
  121. if (kind == Member.ADVICE) return true;
  122. if (!modifiers.matches(sig.getModifiers())) return false;
  123. if (kind == Member.STATIC_INITIALIZATION) {
  124. //System.err.println("match static init: " + sig.getDeclaringType() + " with " + this);
  125. return declaringType.matchesStatically(sig.getDeclaringType().resolve(world));
  126. } else if (kind == Member.FIELD) {
  127. if (!returnType.matchesStatically(sig.getReturnType().resolve(world))) return false;
  128. if (!name.matches(sig.getName())) return false;
  129. boolean ret = declaringTypeMatch(member.getDeclaringType(), member, world);
  130. //System.out.println(" ret: " + ret);
  131. return ret;
  132. } else if (kind == Member.METHOD) {
  133. // Change all this in the face of covariance...
  134. // Check the name
  135. if (!name.matches(sig.getName())) return false;
  136. // Check the parameters
  137. if (!parameterTypes.matches(world.resolve(sig.getParameterTypes()), TypePattern.STATIC).alwaysTrue()) {
  138. return false;
  139. }
  140. // Check the throws pattern
  141. if (!throwsPattern.matches(sig.getExceptions(), world)) return false;
  142. return declaringTypeMatchAllowingForCovariance(member,world,returnType,sig.getReturnType().resolve(world));
  143. } else if (kind == Member.CONSTRUCTOR) {
  144. if (!parameterTypes.matches(world.resolve(sig.getParameterTypes()), TypePattern.STATIC).alwaysTrue()) {
  145. return false;
  146. }
  147. if (!throwsPattern.matches(sig.getExceptions(), world)) return false;
  148. return declaringType.matchesStatically(member.getDeclaringType().resolve(world));
  149. //return declaringTypeMatch(member.getDeclaringType(), member, world);
  150. }
  151. return false;
  152. }
  153. public boolean declaringTypeMatchAllowingForCovariance(Member member,World world,TypePattern returnTypePattern,ResolvedTypeX sigReturn) {
  154. TypeX onTypeUnresolved = member.getDeclaringType();
  155. ResolvedTypeX onType = onTypeUnresolved.resolve(world);
  156. // fastmatch
  157. if (declaringType.matchesStatically(onType) && returnTypePattern.matchesStatically(sigReturn))
  158. return true;
  159. Collection declaringTypes = member.getDeclaringTypes(world);
  160. boolean checkReturnType = true;
  161. // XXX Possible enhancement? Doesn't seem to speed things up
  162. // if (returnTypePattern.isStar()) {
  163. // if (returnTypePattern instanceof WildTypePattern) {
  164. // if (((WildTypePattern)returnTypePattern).getDimensions()==0) checkReturnType = false;
  165. // }
  166. // }
  167. // Sometimes that list includes types that don't explicitly declare the member we are after -
  168. // they are on the list because their supertype is on the list, that's why we use
  169. // lookupMethod rather than lookupMemberNoSupers()
  170. for (Iterator i = declaringTypes.iterator(); i.hasNext(); ) {
  171. ResolvedTypeX type = (ResolvedTypeX)i.next();
  172. if (declaringType.matchesStatically(type)) {
  173. if (!checkReturnType) return true;
  174. ResolvedMember rm = type.lookupMethod(member);
  175. if (rm==null) rm = type.lookupMethodInITDs(member); // It must be in here, or we have *real* problems
  176. TypeX returnTypeX = rm.getReturnType();
  177. ResolvedTypeX returnType = returnTypeX.resolve(world);
  178. if (returnTypePattern.matchesStatically(returnType)) return true;
  179. }
  180. }
  181. return false;
  182. }
  183. // for dynamic join point matching
  184. public boolean matches(JoinPoint.StaticPart jpsp) {
  185. Signature sig = jpsp.getSignature();
  186. if (kind == Member.ADVICE && !(sig instanceof AdviceSignature)) return false;
  187. if (kind == Member.CONSTRUCTOR && !(sig instanceof ConstructorSignature)) return false;
  188. if (kind == Member.FIELD && !(sig instanceof FieldSignature)) return false;
  189. if (kind == Member.METHOD && !(sig instanceof MethodSignature)) return false;
  190. if (kind == Member.STATIC_INITIALIZATION && !(jpsp.getKind().equals(JoinPoint.STATICINITIALIZATION))) return false;
  191. if (kind == Member.POINTCUT) return false;
  192. if (kind == Member.ADVICE) return true;
  193. if (!modifiers.matches(sig.getModifiers())) return false;
  194. if (kind == Member.STATIC_INITIALIZATION) {
  195. //System.err.println("match static init: " + sig.getDeclaringType() + " with " + this);
  196. return declaringType.matchesStatically(sig.getDeclaringType());
  197. } else if (kind == Member.FIELD) {
  198. Class returnTypeClass = ((FieldSignature)sig).getFieldType();
  199. if (!returnType.matchesStatically(returnTypeClass)) return false;
  200. if (!name.matches(sig.getName())) return false;
  201. boolean ret = declaringTypeMatch(sig);
  202. //System.out.println(" ret: " + ret);
  203. return ret;
  204. } else if (kind == Member.METHOD) {
  205. MethodSignature msig = ((MethodSignature)sig);
  206. Class returnTypeClass = msig.getReturnType();
  207. Class[] params = msig.getParameterTypes();
  208. Class[] exceptionTypes = msig.getExceptionTypes();
  209. if (!returnType.matchesStatically(returnTypeClass)) return false;
  210. if (!name.matches(sig.getName())) return false;
  211. if (!parameterTypes.matches(params, TypePattern.STATIC).alwaysTrue()) {
  212. return false;
  213. }
  214. if (!throwsPattern.matches(exceptionTypes)) return false;
  215. return declaringTypeMatch(sig); // XXXAJ5 - Need to make this a covariant aware version for dynamic JP matching to work
  216. } else if (kind == Member.CONSTRUCTOR) {
  217. ConstructorSignature csig = (ConstructorSignature)sig;
  218. Class[] params = csig.getParameterTypes();
  219. Class[] exceptionTypes = csig.getExceptionTypes();
  220. if (!parameterTypes.matches(params, TypePattern.STATIC).alwaysTrue()) {
  221. return false;
  222. }
  223. if (!throwsPattern.matches(exceptionTypes)) return false;
  224. return declaringType.matchesStatically(sig.getDeclaringType());
  225. //return declaringTypeMatch(member.getDeclaringType(), member, world);
  226. }
  227. return false;
  228. }
  229. // For methods, the above covariant aware version (declaringTypeMatchAllowingForCovariance) is used - this version is still here for fields
  230. private boolean declaringTypeMatch(TypeX onTypeUnresolved, Member member, World world) {
  231. ResolvedTypeX onType = onTypeUnresolved.resolve(world);
  232. // fastmatch
  233. if (declaringType.matchesStatically(onType)) return true;
  234. Collection declaringTypes = member.getDeclaringTypes(world);
  235. for (Iterator i = declaringTypes.iterator(); i.hasNext(); ) {
  236. ResolvedTypeX type = (ResolvedTypeX)i.next();
  237. if (declaringType.matchesStatically(type)) return true;
  238. }
  239. return false;
  240. }
  241. private boolean declaringTypeMatch(Signature sig) {
  242. Class onType = sig.getDeclaringType();
  243. if (declaringType.matchesStatically(onType)) return true;
  244. Collection declaringTypes = getDeclaringTypes(sig);
  245. for (Iterator it = declaringTypes.iterator(); it.hasNext(); ) {
  246. Class pClass = (Class) it.next();
  247. if (declaringType.matchesStatically(pClass)) return true;
  248. }
  249. return false;
  250. }
  251. private Collection getDeclaringTypes(Signature sig) {
  252. List l = new ArrayList();
  253. Class onType = sig.getDeclaringType();
  254. String memberName = sig.getName();
  255. if (sig instanceof FieldSignature) {
  256. Class fieldType = ((FieldSignature)sig).getFieldType();
  257. Class superType = onType;
  258. while(superType != null) {
  259. try {
  260. Field f = (superType.getDeclaredField(memberName));
  261. if (f.getType() == fieldType) {
  262. l.add(superType);
  263. }
  264. } catch (NoSuchFieldException nsf) {}
  265. superType = superType.getSuperclass();
  266. }
  267. } else if (sig instanceof MethodSignature) {
  268. Class[] paramTypes = ((MethodSignature)sig).getParameterTypes();
  269. Class superType = onType;
  270. while(superType != null) {
  271. try {
  272. Method m = (superType.getDeclaredMethod(memberName,paramTypes));
  273. l.add(superType);
  274. } catch (NoSuchMethodException nsm) {}
  275. superType = superType.getSuperclass();
  276. }
  277. }
  278. return l;
  279. }
  280. public NamePattern getName() { return name; }
  281. public TypePattern getDeclaringType() { return declaringType; }
  282. public Member.Kind getKind() {
  283. return kind;
  284. }
  285. public String toString() {
  286. StringBuffer buf = new StringBuffer();
  287. if (modifiers != ModifiersPattern.ANY) {
  288. buf.append(modifiers.toString());
  289. buf.append(' ');
  290. }
  291. if (kind == Member.STATIC_INITIALIZATION) {
  292. buf.append(declaringType.toString());
  293. buf.append(".<clinit>()");
  294. } else if (kind == Member.HANDLER) {
  295. buf.append("handler(");
  296. buf.append(parameterTypes.get(0));
  297. buf.append(")");
  298. } else {
  299. if (!(kind == Member.CONSTRUCTOR)) {
  300. buf.append(returnType.toString());
  301. buf.append(' ');
  302. }
  303. if (declaringType != TypePattern.ANY) {
  304. buf.append(declaringType.toString());
  305. buf.append('.');
  306. }
  307. if (kind == Member.CONSTRUCTOR) {
  308. buf.append("new");
  309. } else {
  310. buf.append(name.toString());
  311. }
  312. if (kind == Member.METHOD || kind == Member.CONSTRUCTOR) {
  313. buf.append(parameterTypes.toString());
  314. }
  315. }
  316. return buf.toString();
  317. }
  318. public boolean equals(Object other) {
  319. if (!(other instanceof SignaturePattern)) return false;
  320. SignaturePattern o = (SignaturePattern)other;
  321. return o.kind.equals(this.kind)
  322. && o.modifiers.equals(this.modifiers)
  323. && o.returnType.equals(this.returnType)
  324. && o.declaringType.equals(this.declaringType)
  325. && o.name.equals(this.name)
  326. && o.parameterTypes.equals(this.parameterTypes);
  327. }
  328. public int hashCode() {
  329. int result = 17;
  330. result = 37*result + kind.hashCode();
  331. result = 37*result + modifiers.hashCode();
  332. result = 37*result + returnType.hashCode();
  333. result = 37*result + declaringType.hashCode();
  334. result = 37*result + name.hashCode();
  335. result = 37*result + parameterTypes.hashCode();
  336. return result;
  337. }
  338. public void write(DataOutputStream s) throws IOException {
  339. kind.write(s);
  340. modifiers.write(s);
  341. returnType.write(s);
  342. declaringType.write(s);
  343. name.write(s);
  344. parameterTypes.write(s);
  345. throwsPattern.write(s);
  346. writeLocation(s);
  347. }
  348. public static SignaturePattern read(DataInputStream s, ISourceContext context) throws IOException {
  349. Member.Kind kind = Member.Kind.read(s);
  350. ModifiersPattern modifiers = ModifiersPattern.read(s);
  351. TypePattern returnType = TypePattern.read(s, context);
  352. TypePattern declaringType = TypePattern.read(s, context);
  353. NamePattern name = NamePattern.read(s);
  354. TypePatternList parameterTypes = TypePatternList.read(s, context);
  355. ThrowsPattern throwsPattern = ThrowsPattern.read(s, context);
  356. SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType,
  357. name, parameterTypes, throwsPattern);
  358. ret.readLocation(context, s);
  359. return ret;
  360. }
  361. /**
  362. * @return
  363. */
  364. public ModifiersPattern getModifiers() {
  365. return modifiers;
  366. }
  367. /**
  368. * @return
  369. */
  370. public TypePatternList getParameterTypes() {
  371. return parameterTypes;
  372. }
  373. /**
  374. * @return
  375. */
  376. public TypePattern getReturnType() {
  377. return returnType;
  378. }
  379. /**
  380. * @return
  381. */
  382. public ThrowsPattern getThrowsPattern() {
  383. return throwsPattern;
  384. }
  385. }