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 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  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 v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.patterns;
  13. import java.io.IOException;
  14. import java.util.ArrayList;
  15. import java.util.Collection;
  16. import java.util.Collections;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Set;
  21. import org.aspectj.bridge.ISourceLocation;
  22. import org.aspectj.util.FuzzyBoolean;
  23. import org.aspectj.weaver.AjAttribute;
  24. import org.aspectj.weaver.AjcMemberMaker;
  25. import org.aspectj.weaver.AnnotationTargetKind;
  26. import org.aspectj.weaver.CompressingDataOutputStream;
  27. import org.aspectj.weaver.ConcreteTypeMunger;
  28. import org.aspectj.weaver.ISourceContext;
  29. import org.aspectj.weaver.JoinPointSignature;
  30. import org.aspectj.weaver.JoinPointSignatureIterator;
  31. import org.aspectj.weaver.Member;
  32. import org.aspectj.weaver.MemberKind;
  33. import org.aspectj.weaver.NewFieldTypeMunger;
  34. import org.aspectj.weaver.ResolvableTypeList;
  35. import org.aspectj.weaver.ResolvedMember;
  36. import org.aspectj.weaver.ResolvedType;
  37. import org.aspectj.weaver.UnresolvedType;
  38. import org.aspectj.weaver.VersionedDataInputStream;
  39. import org.aspectj.weaver.World;
  40. public class SignaturePattern extends PatternNode implements ISignaturePattern {
  41. private MemberKind kind;
  42. private ModifiersPattern modifiers;
  43. private TypePattern returnType;
  44. private TypePattern declaringType;
  45. private NamePattern name;
  46. private TypePatternList parameterTypes;
  47. private int bits = 0x0000;
  48. private static final int PARAMETER_ANNOTATION_MATCHING = 0x0001;
  49. private static final int CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING = 0x0002;
  50. private ThrowsPattern throwsPattern;
  51. private AnnotationTypePattern annotationPattern;
  52. private transient int hashcode = -1;
  53. private transient boolean isExactDeclaringTypePattern = false;
  54. public SignaturePattern(MemberKind kind, ModifiersPattern modifiers, TypePattern returnType, TypePattern declaringType,
  55. NamePattern name, TypePatternList parameterTypes, ThrowsPattern throwsPattern, AnnotationTypePattern annotationPattern) {
  56. this.kind = kind;
  57. this.modifiers = modifiers;
  58. this.returnType = returnType;
  59. this.name = name;
  60. this.declaringType = declaringType;
  61. this.parameterTypes = parameterTypes;
  62. this.throwsPattern = throwsPattern;
  63. this.annotationPattern = annotationPattern;
  64. this.isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
  65. }
  66. @Override
  67. public SignaturePattern resolveBindings(IScope scope, Bindings bindings) {
  68. if (returnType != null) {
  69. returnType = returnType.resolveBindings(scope, bindings, false, false);
  70. checkForIncorrectTargetKind(returnType, scope, false);
  71. }
  72. if (declaringType != null) {
  73. declaringType = declaringType.resolveBindings(scope, bindings, false, false);
  74. checkForIncorrectTargetKind(declaringType, scope, false);
  75. isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
  76. }
  77. if (parameterTypes != null) {
  78. parameterTypes = parameterTypes.resolveBindings(scope, bindings, false, false);
  79. checkForIncorrectTargetKind(parameterTypes, scope, false, true);
  80. }
  81. if (throwsPattern != null) {
  82. throwsPattern = throwsPattern.resolveBindings(scope, bindings);
  83. if (throwsPattern.getForbidden().getTypePatterns().length > 0
  84. || throwsPattern.getRequired().getTypePatterns().length > 0) {
  85. checkForIncorrectTargetKind(throwsPattern, scope, false);
  86. }
  87. }
  88. if (annotationPattern != null) {
  89. annotationPattern = annotationPattern.resolveBindings(scope, bindings, false);
  90. checkForIncorrectTargetKind(annotationPattern, scope, true);
  91. }
  92. hashcode = -1;
  93. return this;
  94. }
  95. private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed) {
  96. checkForIncorrectTargetKind(patternNode, scope, targetsOtherThanTypeAllowed, false);
  97. }
  98. // bug 115252 - adding an xlint warning if the annnotation target type is
  99. // wrong. This logic, or similar, may have to be applied elsewhere in the case
  100. // of pointcuts which don't go through SignaturePattern.resolveBindings(..)
  101. private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed,
  102. boolean parameterTargettingAnnotationsAllowed) {
  103. // return if we're not in java5 mode, if the unmatchedTargetKind Xlint
  104. // warning has been turned off, or if the patternNode is *
  105. if (!scope.getWorld().isInJava5Mode() || scope.getWorld().getLint().unmatchedTargetKind == null
  106. || (patternNode instanceof AnyTypePattern)) {
  107. return;
  108. }
  109. if (patternNode instanceof ExactAnnotationTypePattern) {
  110. ResolvedType resolvedType = ((ExactAnnotationTypePattern) patternNode).getAnnotationType().resolve(scope.getWorld());
  111. if (targetsOtherThanTypeAllowed) {
  112. AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
  113. if (targetKinds == null) {
  114. return;
  115. }
  116. reportUnmatchedTargetKindMessage(targetKinds, patternNode, scope, true);
  117. } else if (!targetsOtherThanTypeAllowed && !resolvedType.canAnnotationTargetType()) {
  118. // everything is incorrect since we've already checked whether we have the TYPE target annotation
  119. AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
  120. if (targetKinds == null) {
  121. return;
  122. }
  123. reportUnmatchedTargetKindMessage(targetKinds, patternNode, scope, false);
  124. }
  125. } else {
  126. TypePatternVisitor visitor = new TypePatternVisitor(scope, targetsOtherThanTypeAllowed,
  127. parameterTargettingAnnotationsAllowed);
  128. patternNode.traverse(visitor, null);
  129. if (visitor.containedIncorrectTargetKind()) {
  130. Set<ExactAnnotationTypePattern> keys = visitor.getIncorrectTargetKinds().keySet();
  131. for (PatternNode node : keys) {
  132. AnnotationTargetKind[] targetKinds = visitor.getIncorrectTargetKinds().get(node);
  133. reportUnmatchedTargetKindMessage(targetKinds, node, scope, false);
  134. }
  135. }
  136. }
  137. }
  138. private void reportUnmatchedTargetKindMessage(AnnotationTargetKind[] annotationTargetKinds, PatternNode node, IScope scope,
  139. boolean checkMatchesMemberKindName) {
  140. StringBuilder targetNames = new StringBuilder("{");
  141. for (int i = 0; i < annotationTargetKinds.length; i++) {
  142. AnnotationTargetKind targetKind = annotationTargetKinds[i];
  143. if (checkMatchesMemberKindName && kind.getName().equals(targetKind.getName())) {
  144. return;
  145. }
  146. if (i < (annotationTargetKinds.length - 1)) {
  147. targetNames.append("ElementType." + targetKind.getName() + ",");
  148. } else {
  149. targetNames.append("ElementType." + targetKind.getName() + "}");
  150. }
  151. }
  152. scope.getWorld().getLint().unmatchedTargetKind.signal(new String[] { node.toString(), targetNames.toString() },
  153. getSourceLocation(), new ISourceLocation[0]);
  154. }
  155. /**
  156. * Class which visits the nodes in the TypePattern tree until an ExactTypePattern is found. Once this is found it creates a new
  157. * ExactAnnotationTypePattern and checks whether the targetKind (created via the @Target annotation) matches ElementType.TYPE if
  158. * this is the only target kind which is allowed, or matches the signature pattern kind if there is no restriction.
  159. */
  160. private class TypePatternVisitor extends AbstractPatternNodeVisitor {
  161. private IScope scope;
  162. private Map<ExactAnnotationTypePattern, AnnotationTargetKind[]> incorrectTargetKinds = new HashMap<>();
  163. private boolean targetsOtherThanTypeAllowed;
  164. private boolean parameterTargettingAnnotationsAllowed;
  165. /**
  166. * @param requiredTarget - the signature pattern Kind
  167. * @param scope
  168. * @param parameterTargettingAnnotationsAllowed
  169. */
  170. public TypePatternVisitor(IScope scope, boolean targetsOtherThanTypeAllowed, boolean parameterTargettingAnnotationsAllowed) {
  171. this.scope = scope;
  172. this.targetsOtherThanTypeAllowed = targetsOtherThanTypeAllowed;
  173. this.parameterTargettingAnnotationsAllowed = parameterTargettingAnnotationsAllowed;
  174. }
  175. @Override
  176. public Object visit(WildAnnotationTypePattern node, Object data) {
  177. node.getTypePattern().accept(this, data);
  178. return node;
  179. }
  180. /**
  181. * Do the ExactAnnotationTypePatterns have the incorrect target?
  182. */
  183. @Override
  184. public Object visit(ExactAnnotationTypePattern node, Object data) {
  185. ResolvedType resolvedType = node.getAnnotationType().resolve(scope.getWorld());
  186. if (targetsOtherThanTypeAllowed) {
  187. AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
  188. if (targetKinds == null) {
  189. return data;
  190. }
  191. List<AnnotationTargetKind> incorrectTargets = new ArrayList<>();
  192. for (AnnotationTargetKind targetKind : targetKinds) {
  193. if (targetKind.getName().equals(kind.getName())
  194. || (targetKind.getName().equals("PARAMETER") && node.isForParameterAnnotationMatch())) {
  195. return data;
  196. }
  197. incorrectTargets.add(targetKind);
  198. }
  199. if (incorrectTargets.isEmpty()) {
  200. return data;
  201. }
  202. AnnotationTargetKind[] kinds = new AnnotationTargetKind[incorrectTargets.size()];
  203. incorrectTargetKinds.put(node, incorrectTargets.toArray(kinds));
  204. } else if (!targetsOtherThanTypeAllowed && !resolvedType.canAnnotationTargetType()) {
  205. AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
  206. if (targetKinds == null) {
  207. return data;
  208. }
  209. // exception here is if parameter annotations are allowed
  210. if (parameterTargettingAnnotationsAllowed) {
  211. for (AnnotationTargetKind annotationTargetKind : targetKinds) {
  212. if (annotationTargetKind.getName().equals("PARAMETER") && node.isForParameterAnnotationMatch()) {
  213. return data;
  214. }
  215. }
  216. }
  217. incorrectTargetKinds.put(node, targetKinds);
  218. }
  219. return data;
  220. }
  221. @Override
  222. public Object visit(ExactTypePattern node, Object data) {
  223. ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(node.getExactType().resolve(scope.getWorld()), null);
  224. eatp.accept(this, data);
  225. return data;
  226. }
  227. @Override
  228. public Object visit(AndTypePattern node, Object data) {
  229. node.getLeft().accept(this, data);
  230. node.getRight().accept(this, data);
  231. return node;
  232. }
  233. @Override
  234. public Object visit(OrTypePattern node, Object data) {
  235. node.getLeft().accept(this, data);
  236. node.getRight().accept(this, data);
  237. return node;
  238. }
  239. @Override
  240. public Object visit(AnyWithAnnotationTypePattern node, Object data) {
  241. node.getAnnotationPattern().accept(this, data);
  242. return node;
  243. }
  244. public boolean containedIncorrectTargetKind() {
  245. return (incorrectTargetKinds.size() != 0);
  246. }
  247. public Map<ExactAnnotationTypePattern, AnnotationTargetKind[]> getIncorrectTargetKinds() {
  248. return incorrectTargetKinds;
  249. }
  250. }
  251. public void postRead(ResolvedType enclosingType) {
  252. if (returnType != null) {
  253. returnType.postRead(enclosingType);
  254. }
  255. if (declaringType != null) {
  256. declaringType.postRead(enclosingType);
  257. }
  258. if (parameterTypes != null) {
  259. parameterTypes.postRead(enclosingType);
  260. }
  261. }
  262. /**
  263. * return a copy of this signature pattern in which every type variable reference is replaced by the corresponding entry in the
  264. * map.
  265. */
  266. @Override
  267. public SignaturePattern parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
  268. SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType.parameterizeWith(typeVariableMap, w), declaringType
  269. .parameterizeWith(typeVariableMap, w), name, parameterTypes.parameterizeWith(typeVariableMap, w), throwsPattern
  270. .parameterizeWith(typeVariableMap, w), annotationPattern.parameterizeWith(typeVariableMap, w));
  271. ret.copyLocationFrom(this);
  272. return ret;
  273. }
  274. @Override
  275. public boolean matches(Member joinPointSignature, World world, boolean allowBridgeMethods) {
  276. // fail (or succeed!) fast tests...
  277. if (joinPointSignature == null) {
  278. return false;
  279. }
  280. if (kind != joinPointSignature.getKind()) {
  281. return false;
  282. }
  283. if (kind == Member.ADVICE) {
  284. return true;
  285. }
  286. // do the hard work then...
  287. boolean subjectMatch = true;
  288. boolean wantsAnnotationMatch = wantToMatchAnnotationPattern();
  289. JoinPointSignatureIterator candidateMatches = joinPointSignature.getJoinPointSignatures(world);
  290. while (candidateMatches.hasNext()) {
  291. JoinPointSignature aSig = candidateMatches.next();
  292. // System.out.println(aSig);
  293. FuzzyBoolean matchResult = matchesExactly(aSig, world, allowBridgeMethods, subjectMatch);
  294. if (matchResult.alwaysTrue()) {
  295. return true;
  296. } else if (matchResult.alwaysFalse()) {
  297. return false;
  298. }
  299. // if we got a "MAYBE" it's worth looking at the other signatures
  300. // The first signature is the subject signature - and against it we must match modifiers/annotations/throws
  301. // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
  302. subjectMatch = false;
  303. // Early exit
  304. if (wantsAnnotationMatch) {
  305. return false;
  306. }
  307. }
  308. return false;
  309. }
  310. // Does this pattern match this exact signature (no declaring type mucking about
  311. // or chasing up the hierarchy)
  312. // return YES if it does, NO if it doesn't and no ancester member could match either,
  313. // and MAYBE if it doesn't but an ancester member could.
  314. private FuzzyBoolean matchesExactly(JoinPointSignature aMember, World inAWorld, boolean allowBridgeMethods, boolean subjectMatch) {
  315. // Java5 introduces bridge methods, we match a call to them but nothing else...
  316. if (aMember.isBridgeMethod() && !allowBridgeMethods) {
  317. return FuzzyBoolean.MAYBE;
  318. }
  319. // Only the subject is checked for modifiers
  320. // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
  321. if (subjectMatch && !modifiers.matches(aMember.getModifiers())) {
  322. return FuzzyBoolean.NO;
  323. }
  324. FuzzyBoolean matchesIgnoringAnnotations = FuzzyBoolean.YES;
  325. if (kind == Member.STATIC_INITIALIZATION) {
  326. matchesIgnoringAnnotations = matchesExactlyStaticInitialization(aMember, inAWorld);
  327. } else if (kind == Member.FIELD) {
  328. matchesIgnoringAnnotations = matchesExactlyField(aMember, inAWorld);
  329. } else if (kind == Member.METHOD) {
  330. matchesIgnoringAnnotations = matchesExactlyMethod(aMember, inAWorld, subjectMatch);
  331. } else if (kind == Member.CONSTRUCTOR) {
  332. matchesIgnoringAnnotations = matchesExactlyConstructor(aMember, inAWorld);
  333. }
  334. if (matchesIgnoringAnnotations.alwaysFalse()) {
  335. return FuzzyBoolean.NO;
  336. }
  337. // Only the subject is checked for annotations (239441/119749)
  338. // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
  339. if (subjectMatch) {
  340. // The annotations must match if specified
  341. if (!matchesAnnotations(aMember, inAWorld).alwaysTrue()) {
  342. return FuzzyBoolean.NO;
  343. } else {
  344. return matchesIgnoringAnnotations;
  345. }
  346. } else {
  347. // Unless they specified any annotation then it is a failure
  348. if (annotationPattern instanceof AnyAnnotationTypePattern) {
  349. return matchesIgnoringAnnotations;
  350. } else {
  351. return FuzzyBoolean.NO;
  352. }
  353. }
  354. // if (subjectMatch && !matchesAnnotations(aMember, inAWorld).alwaysTrue()) {
  355. // return FuzzyBoolean.NO;
  356. // } else {
  357. //
  358. // return matchesIgnoringAnnotations;
  359. // }
  360. }
  361. private boolean wantToMatchAnnotationPattern() {
  362. return !(annotationPattern instanceof AnyAnnotationTypePattern);
  363. }
  364. /**
  365. * Matches on declaring type
  366. */
  367. private FuzzyBoolean matchesExactlyStaticInitialization(JoinPointSignature aMember, World world) {
  368. return FuzzyBoolean.fromBoolean(declaringType.matchesStatically(aMember.getDeclaringType().resolve(world)));
  369. }
  370. /**
  371. * Matches on name, declaring type, field type
  372. */
  373. private FuzzyBoolean matchesExactlyField(JoinPointSignature aField, World world) {
  374. if (!name.matches(aField.getName())) {
  375. return FuzzyBoolean.NO;
  376. }
  377. ResolvedType fieldDeclaringType = aField.getDeclaringType().resolve(world);
  378. if (!declaringType.matchesStatically(fieldDeclaringType)) {
  379. return FuzzyBoolean.MAYBE;
  380. }
  381. if (!returnType.matchesStatically(aField.getReturnType().resolve(world))) {
  382. // looking bad, but there might be parameterization to consider...
  383. if (!returnType.matchesStatically(aField.getGenericReturnType().resolve(world))) {
  384. // ok, it's bad.
  385. return FuzzyBoolean.MAYBE;
  386. }
  387. }
  388. // passed all the guards...
  389. return FuzzyBoolean.YES;
  390. }
  391. /**
  392. * Quickly detect if the joinpoint absolutely cannot match becaused the method parameters at the joinpoint cannot match against
  393. * this signature pattern.
  394. *
  395. * @param methodJoinpoint the joinpoint to quickly match against
  396. * @return true if it is impossible for the joinpoint to match this signature
  397. */
  398. private boolean parametersCannotMatch(JoinPointSignature methodJoinpoint) {
  399. if (methodJoinpoint.isVarargsMethod()) {
  400. // just give up early (for now)
  401. return false;
  402. }
  403. int patternParameterCount = parameterTypes.size();
  404. if (patternParameterCount == 0 || parameterTypes.ellipsisCount == 0) {
  405. boolean equalCount = patternParameterCount == methodJoinpoint.getParameterTypes().length;
  406. // Quick rule: pattern specifies zero parameters, and joinpoint has parameters *OR*
  407. if (patternParameterCount == 0 && !equalCount) {
  408. return true;
  409. }
  410. // Quick rule: pattern doesn't specify ellipsis and there are a different number of parameters on the
  411. // method join point as compared with the pattern
  412. if (parameterTypes.ellipsisCount == 0 && !equalCount) {
  413. if (patternParameterCount > 0 && parameterTypes.get(patternParameterCount - 1).isVarArgs()) {
  414. return false;
  415. }
  416. return true;
  417. }
  418. }
  419. return false;
  420. }
  421. /**
  422. * Matches on name, declaring type, return type, parameter types, throws types
  423. */
  424. private FuzzyBoolean matchesExactlyMethod(JoinPointSignature aMethod, World world, boolean subjectMatch) {
  425. if (parametersCannotMatch(aMethod)) {
  426. // System.err.println("Parameter types pattern " + parameterTypes + " pcount: " + aMethod.getParameterTypes().length);
  427. return FuzzyBoolean.NO;
  428. }
  429. // OPTIMIZE only for exact match do the pattern match now? Otherwise defer it until other fast checks complete?
  430. if (!name.matches(aMethod.getName())) {
  431. return FuzzyBoolean.NO;
  432. }
  433. // Check the throws pattern
  434. if (subjectMatch && !throwsPattern.matches(aMethod.getExceptions(), world)) {
  435. return FuzzyBoolean.NO;
  436. }
  437. // '*' trivially matches everything, no need to check further
  438. if (!declaringType.isStar()) {
  439. if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) {
  440. return FuzzyBoolean.MAYBE;
  441. }
  442. }
  443. // '*' would match any return value
  444. if (!returnType.isStar()) {
  445. boolean b = returnType.isBangVoid();
  446. if (b) {
  447. String s = aMethod.getReturnType().getSignature();
  448. if (s.length() == 1 && s.charAt(0) == 'V') {
  449. // it is void, so not a match
  450. return FuzzyBoolean.NO;
  451. }
  452. } else {
  453. if (returnType.isVoid()) {
  454. String s = aMethod.getReturnType().getSignature();
  455. if (s.length() != 1 || s.charAt(0) != 'V') {
  456. // it is not void, so not a match
  457. return FuzzyBoolean.NO;
  458. }
  459. } else {
  460. if (!returnType.matchesStatically(aMethod.getReturnType().resolve(world))) {
  461. // looking bad, but there might be parameterization to consider...
  462. if (!returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) {
  463. // ok, it's bad.
  464. return FuzzyBoolean.MAYBE;
  465. }
  466. }
  467. }
  468. }
  469. }
  470. // The most simple case: pattern is (..) will match anything
  471. if (parameterTypes.size() == 1 && parameterTypes.get(0).isEllipsis()) {
  472. return FuzzyBoolean.YES;
  473. }
  474. if (!parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) {
  475. return FuzzyBoolean.NO;
  476. }
  477. // OPTIMIZE both resolution of these types and their annotations should be deferred - just pass down a world and do it lower
  478. // down
  479. // ResolvedType[] resolvedParameters = world.resolve(aMethod.getParameterTypes());
  480. ResolvableTypeList rtl = new ResolvableTypeList(world, aMethod.getParameterTypes());
  481. // Only fetch the parameter annotations if the pointcut is going to be matching on them
  482. ResolvedType[][] parameterAnnotationTypes = null;
  483. if (isMatchingParameterAnnotations()) {
  484. parameterAnnotationTypes = aMethod.getParameterAnnotationTypes();
  485. if (parameterAnnotationTypes != null && parameterAnnotationTypes.length == 0) {
  486. parameterAnnotationTypes = null;
  487. }
  488. }
  489. if (!parameterTypes.matches(rtl, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
  490. // It could still be a match based on the generic sig parameter types of a parameterized type
  491. if (!parameterTypes.matches(new ResolvableTypeList(world, aMethod.getGenericParameterTypes()), TypePattern.STATIC,
  492. parameterAnnotationTypes).alwaysTrue()) {
  493. return FuzzyBoolean.MAYBE;
  494. // It could STILL be a match based on the erasure of the parameter types??
  495. // to be determined via test cases...
  496. }
  497. }
  498. // check that varargs specifications match
  499. if (!matchesVarArgs(aMethod, world)) {
  500. return FuzzyBoolean.MAYBE;
  501. }
  502. // passed all the guards..
  503. return FuzzyBoolean.YES;
  504. }
  505. /**
  506. * Determine if any pattern in the parameter type pattern list is attempting to match on parameter annotations.
  507. *
  508. * @return true if a parameter type pattern wants to match on a parameter annotation
  509. */
  510. private boolean isMatchingParameterAnnotations() {
  511. if ((bits & CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING) == 0) {
  512. bits |= CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING;
  513. for (int tp = 0, max = parameterTypes.size(); tp < max; tp++) {
  514. TypePattern typePattern = parameterTypes.get(tp);
  515. if (isParameterAnnotationMatching(typePattern)) {
  516. bits |= PARAMETER_ANNOTATION_MATCHING;
  517. }
  518. }
  519. }
  520. return (bits & PARAMETER_ANNOTATION_MATCHING) != 0;
  521. }
  522. /**
  523. * Walk the simple structure of a type pattern and determine if any leaf node is involved in parameter annotation matching.
  524. */
  525. private boolean isParameterAnnotationMatching(TypePattern tp) {
  526. if (tp instanceof OrTypePattern) {
  527. OrTypePattern orAtp = (OrTypePattern) tp;
  528. return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
  529. } else if (tp instanceof AndTypePattern) {
  530. AndTypePattern andAtp = (AndTypePattern) tp;
  531. return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
  532. } else if (tp instanceof NotTypePattern) {
  533. NotTypePattern notAtp = (NotTypePattern) tp;
  534. return (isParameterAnnotationMatching(notAtp.getNegatedPattern()));
  535. } else {
  536. AnnotationTypePattern atp = tp.getAnnotationPattern();
  537. return isParameterAnnotationMatching(atp);
  538. }
  539. }
  540. private boolean isParameterAnnotationMatching(AnnotationTypePattern tp) {
  541. if (tp instanceof OrAnnotationTypePattern) {
  542. OrAnnotationTypePattern orAtp = (OrAnnotationTypePattern) tp;
  543. return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
  544. } else if (tp instanceof AndAnnotationTypePattern) {
  545. AndAnnotationTypePattern andAtp = (AndAnnotationTypePattern) tp;
  546. return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
  547. } else if (tp instanceof NotAnnotationTypePattern) {
  548. NotAnnotationTypePattern notAtp = (NotAnnotationTypePattern) tp;
  549. return (isParameterAnnotationMatching(notAtp.negatedPattern));
  550. } else {
  551. return tp.isForParameterAnnotationMatch();
  552. }
  553. }
  554. /**
  555. * match on declaring type, parameter types, throws types
  556. */
  557. private FuzzyBoolean matchesExactlyConstructor(JoinPointSignature aConstructor, World world) {
  558. if (!declaringType.matchesStatically(aConstructor.getDeclaringType().resolve(world))) {
  559. return FuzzyBoolean.NO;
  560. }
  561. if (!parameterTypes.canMatchSignatureWithNParameters(aConstructor.getParameterTypes().length)) {
  562. return FuzzyBoolean.NO;
  563. }
  564. ResolvedType[] resolvedParameters = world.resolve(aConstructor.getParameterTypes());
  565. ResolvedType[][] parameterAnnotationTypes = aConstructor.getParameterAnnotationTypes();
  566. if (parameterAnnotationTypes == null || parameterAnnotationTypes.length == 0) {
  567. parameterAnnotationTypes = null;
  568. }
  569. if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
  570. // It could still be a match based on the generic sig parameter types of a parameterized type
  571. if (!parameterTypes.matches(world.resolve(aConstructor.getGenericParameterTypes()), TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
  572. return FuzzyBoolean.MAYBE;
  573. // It could STILL be a match based on the erasure of the parameter types??
  574. // to be determined via test cases...
  575. }
  576. }
  577. // check that varargs specifications match
  578. if (!matchesVarArgs(aConstructor, world)) {
  579. return FuzzyBoolean.NO;
  580. }
  581. // Check the throws pattern
  582. if (!throwsPattern.matches(aConstructor.getExceptions(), world)) {
  583. return FuzzyBoolean.NO;
  584. }
  585. // passed all the guards..
  586. return FuzzyBoolean.YES;
  587. }
  588. /**
  589. * We've matched against this method or constructor so far, but without considering varargs (which has been matched as a simple
  590. * array thus far). Now we do the additional checks to see if the parties agree on whether the last parameter is varargs or a
  591. * straight array.
  592. */
  593. private boolean matchesVarArgs(JoinPointSignature aMethodOrConstructor, World inAWorld) {
  594. if (parameterTypes.size() == 0) {
  595. return true;
  596. }
  597. TypePattern lastPattern = parameterTypes.get(parameterTypes.size() - 1);
  598. boolean canMatchVarArgsSignature = lastPattern.isStar() || lastPattern.isVarArgs() || (lastPattern == TypePattern.ELLIPSIS);
  599. if (aMethodOrConstructor.isVarargsMethod()) {
  600. // we have at least one parameter in the pattern list, and the method has a varargs signature
  601. if (!canMatchVarArgsSignature) {
  602. // XXX - Ideally the shadow would be included in the msg but we don't know it...
  603. inAWorld.getLint().cantMatchArrayTypeOnVarargs.signal(aMethodOrConstructor.toString(), getSourceLocation());
  604. return false;
  605. }
  606. } else {
  607. // the method ends with an array type, check that we don't *require* a varargs
  608. if (lastPattern.isVarArgs()) {
  609. return false;
  610. }
  611. }
  612. return true;
  613. }
  614. private FuzzyBoolean matchesAnnotations(ResolvedMember member, World world) {
  615. if (member == null) {
  616. // world.getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
  617. return FuzzyBoolean.NO;
  618. }
  619. annotationPattern.resolve(world);
  620. // optimization before we go digging around for annotations on ITDs
  621. if (annotationPattern instanceof AnyAnnotationTypePattern) {
  622. return FuzzyBoolean.YES;
  623. }
  624. // fake members represent ITD'd fields - for their annotations we should go and look up the
  625. // relevant member in the original aspect
  626. if (member.isAnnotatedElsewhere() && member.getKind() == Member.FIELD) {
  627. // FIXME asc duplicate of code in AnnotationPointcut.matchInternal()? same fixmes apply here.
  628. // ResolvedMember [] mems = member.getDeclaringType().resolve(world).getDeclaredFields(); // FIXME asc should include
  629. // supers with getInterTypeMungersIncludingSupers?
  630. List<ConcreteTypeMunger> mungers = member.getDeclaringType().resolve(world).getInterTypeMungers();
  631. for (ConcreteTypeMunger typeMunger : mungers) {
  632. if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
  633. ResolvedMember fakerm = typeMunger.getSignature();
  634. ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
  635. ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
  636. if (fakerm.equals(member)) {
  637. member = rmm;
  638. }
  639. }
  640. }
  641. }
  642. if (annotationPattern.matches(member).alwaysTrue()) {
  643. return FuzzyBoolean.YES;
  644. } else {
  645. // do NOT look at ancestor members... only the subject can have an annotation match
  646. // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
  647. return FuzzyBoolean.NO;
  648. }
  649. }
  650. private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
  651. ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
  652. for (ResolvedMember member : decMethods) {
  653. if (member.equals(ajcMethod)) {
  654. return member;
  655. }
  656. }
  657. return null;
  658. }
  659. public boolean declaringTypeMatchAllowingForCovariance(Member member, UnresolvedType shadowDeclaringType, World world,
  660. TypePattern returnTypePattern, ResolvedType sigReturn) {
  661. ResolvedType onType = shadowDeclaringType.resolve(world);
  662. // fastmatch
  663. if (declaringType.matchesStatically(onType) && returnTypePattern.matchesStatically(sigReturn)) {
  664. return true;
  665. }
  666. Collection<ResolvedType> declaringTypes = member.getDeclaringTypes(world);
  667. boolean checkReturnType = true;
  668. // XXX Possible enhancement? Doesn't seem to speed things up
  669. // if (returnTypePattern.isStar()) {
  670. // if (returnTypePattern instanceof WildTypePattern) {
  671. // if (((WildTypePattern)returnTypePattern).getDimensions()==0) checkReturnType = false;
  672. // }
  673. // }
  674. // Sometimes that list includes types that don't explicitly declare the member we are after -
  675. // they are on the list because their supertype is on the list, that's why we use
  676. // lookupMethod rather than lookupMemberNoSupers()
  677. for (ResolvedType type : declaringTypes) {
  678. if (declaringType.matchesStatically(type)) {
  679. if (!checkReturnType) {
  680. return true;
  681. }
  682. ResolvedMember rm = type.lookupMethod(member);
  683. if (rm == null) {
  684. rm = type.lookupMethodInITDs(member); // It must be in here, or we have *real* problems
  685. }
  686. if (rm == null) {
  687. continue; // might be currently looking at the generic type and we need to continue searching in case we hit a
  688. }
  689. // parameterized version of this same type...
  690. UnresolvedType returnTypeX = rm.getReturnType();
  691. ResolvedType returnType = returnTypeX.resolve(world);
  692. if (returnTypePattern.matchesStatically(returnType)) {
  693. return true;
  694. }
  695. }
  696. }
  697. return false;
  698. }
  699. // private Collection getDeclaringTypes(Signature sig) {
  700. // List l = new ArrayList();
  701. // Class onType = sig.getDeclaringType();
  702. // String memberName = sig.getName();
  703. // if (sig instanceof FieldSignature) {
  704. // Class fieldType = ((FieldSignature)sig).getFieldType();
  705. // Class superType = onType;
  706. // while(superType != null) {
  707. // try {
  708. // Field f = (superType.getDeclaredField(memberName));
  709. // if (f.getType() == fieldType) {
  710. // l.add(superType);
  711. // }
  712. // } catch (NoSuchFieldException nsf) {}
  713. // superType = superType.getSuperclass();
  714. // }
  715. // } else if (sig instanceof MethodSignature) {
  716. // Class[] paramTypes = ((MethodSignature)sig).getParameterTypes();
  717. // Class superType = onType;
  718. // while(superType != null) {
  719. // try {
  720. // superType.getDeclaredMethod(memberName,paramTypes);
  721. // l.add(superType);
  722. // } catch (NoSuchMethodException nsm) {}
  723. // superType = superType.getSuperclass();
  724. // }
  725. // }
  726. // return l;
  727. // }
  728. public NamePattern getName() {
  729. return name;
  730. }
  731. public TypePattern getDeclaringType() {
  732. return declaringType;
  733. }
  734. public MemberKind getKind() {
  735. return kind;
  736. }
  737. @Override
  738. public String toString() {
  739. StringBuilder buf = new StringBuilder();
  740. if (annotationPattern != AnnotationTypePattern.ANY) {
  741. buf.append(annotationPattern.toString());
  742. buf.append(' ');
  743. }
  744. if (modifiers != ModifiersPattern.ANY) {
  745. buf.append(modifiers.toString());
  746. buf.append(' ');
  747. }
  748. if (kind == Member.STATIC_INITIALIZATION) {
  749. buf.append(declaringType.toString());
  750. buf.append(".<clinit>()");// FIXME AV - bad, cannot be parsed again
  751. } else if (kind == Member.HANDLER) {
  752. buf.append("handler(");
  753. buf.append(parameterTypes.get(0));
  754. buf.append(")");
  755. } else {
  756. if (!(kind == Member.CONSTRUCTOR)) {
  757. buf.append(returnType.toString());
  758. buf.append(' ');
  759. }
  760. if (declaringType != TypePattern.ANY) {
  761. buf.append(declaringType.toString());
  762. buf.append('.');
  763. }
  764. if (kind == Member.CONSTRUCTOR) {
  765. buf.append("new");
  766. } else {
  767. buf.append(name.toString());
  768. }
  769. if (kind == Member.METHOD || kind == Member.CONSTRUCTOR) {
  770. buf.append(parameterTypes.toString());
  771. }
  772. // FIXME AV - throws is not printed here, weird
  773. }
  774. return buf.toString();
  775. }
  776. @Override
  777. public boolean equals(Object other) {
  778. if (!(other instanceof SignaturePattern)) {
  779. return false;
  780. }
  781. SignaturePattern o = (SignaturePattern) other;
  782. return o.kind.equals(this.kind) && o.modifiers.equals(this.modifiers) && o.returnType.equals(this.returnType)
  783. && o.declaringType.equals(this.declaringType) && o.name.equals(this.name)
  784. && o.parameterTypes.equals(this.parameterTypes) && o.throwsPattern.equals(this.throwsPattern)
  785. && o.annotationPattern.equals(this.annotationPattern);
  786. }
  787. @Override
  788. public int hashCode() {
  789. if (hashcode == -1) {
  790. hashcode = 17;
  791. hashcode = 37 * hashcode + kind.hashCode();
  792. hashcode = 37 * hashcode + modifiers.hashCode();
  793. hashcode = 37 * hashcode + returnType.hashCode();
  794. hashcode = 37 * hashcode + declaringType.hashCode();
  795. hashcode = 37 * hashcode + name.hashCode();
  796. hashcode = 37 * hashcode + parameterTypes.hashCode();
  797. hashcode = 37 * hashcode + throwsPattern.hashCode();
  798. hashcode = 37 * hashcode + annotationPattern.hashCode();
  799. }
  800. return hashcode;
  801. }
  802. @Override
  803. public void write(CompressingDataOutputStream s) throws IOException {
  804. kind.write(s);
  805. modifiers.write(s);
  806. returnType.write(s);
  807. declaringType.write(s);
  808. name.write(s);
  809. parameterTypes.write(s);
  810. throwsPattern.write(s);
  811. annotationPattern.write(s);
  812. writeLocation(s);
  813. }
  814. public static SignaturePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  815. // ISignaturePattern kind should already have been read by the time this read is entered
  816. MemberKind kind = MemberKind.read(s);
  817. ModifiersPattern modifiers = ModifiersPattern.read(s);
  818. TypePattern returnType = TypePattern.read(s, context);
  819. TypePattern declaringType = TypePattern.read(s, context);
  820. NamePattern name = NamePattern.read(s);
  821. TypePatternList parameterTypes = TypePatternList.read(s, context);
  822. ThrowsPattern throwsPattern = ThrowsPattern.read(s, context);
  823. AnnotationTypePattern annotationPattern = AnnotationTypePattern.ANY;
  824. if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
  825. annotationPattern = AnnotationTypePattern.read(s, context);
  826. }
  827. SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
  828. throwsPattern, annotationPattern);
  829. ret.readLocation(context, s);
  830. return ret;
  831. }
  832. /**
  833. * @return
  834. */
  835. public ModifiersPattern getModifiers() {
  836. return modifiers;
  837. }
  838. /**
  839. * @return
  840. */
  841. public TypePatternList getParameterTypes() {
  842. return parameterTypes;
  843. }
  844. /**
  845. * @return
  846. */
  847. public TypePattern getReturnType() {
  848. return returnType;
  849. }
  850. /**
  851. * @return
  852. */
  853. public ThrowsPattern getThrowsPattern() {
  854. return throwsPattern;
  855. }
  856. /**
  857. * return true if last argument in params is an Object[] but the modifiers say this method was declared with varargs
  858. * (Object...). We shouldn't be matching if this is the case.
  859. */
  860. // private boolean matchedArrayAgainstVarArgs(TypePatternList params,int modifiers) {
  861. // if (params.size()>0 && (modifiers & Constants.ACC_VARARGS)!=0) {
  862. // // we have at least one parameter in the pattern list, and the method has a varargs signature
  863. // TypePattern lastPattern = params.get(params.size()-1);
  864. // if (lastPattern.isArray() && !lastPattern.isVarArgs) return true;
  865. // }
  866. // return false;
  867. // }
  868. public AnnotationTypePattern getAnnotationPattern() {
  869. return annotationPattern;
  870. }
  871. @Override
  872. public boolean isStarAnnotation() {
  873. return annotationPattern == AnnotationTypePattern.ANY;
  874. }
  875. @Override
  876. public Object accept(PatternNodeVisitor visitor, Object data) {
  877. return visitor.visit(this, data);
  878. }
  879. public boolean isExactDeclaringTypePattern() {
  880. return isExactDeclaringTypePattern;
  881. }
  882. @Override
  883. public boolean isMatchOnAnyName() {
  884. return getName().isAny();
  885. }
  886. @Override
  887. public List<ExactTypePattern> getExactDeclaringTypes() {
  888. if (declaringType instanceof ExactTypePattern) {
  889. List<ExactTypePattern> l = new ArrayList<>();
  890. l.add((ExactTypePattern) declaringType);
  891. return l;
  892. } else {
  893. return Collections.emptyList();
  894. }
  895. }
  896. @Override
  897. public boolean couldEverMatch(ResolvedType type) {
  898. return declaringType.matches(type, TypePattern.STATIC).maybeTrue();
  899. }
  900. }