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

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. }