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

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