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

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.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 (!returnType.matchesArray(aMethod.getReturnType())) {
  426. return FuzzyBoolean.NO;
  427. }
  428. if (parametersCannotMatch(aMethod)) {
  429. // System.err.println("Parameter types pattern " + parameterTypes + " pcount: " + aMethod.getParameterTypes().length);
  430. return FuzzyBoolean.NO;
  431. }
  432. // OPTIMIZE only for exact match do the pattern match now? Otherwise defer it until other fast checks complete?
  433. if (!name.matches(aMethod.getName())) {
  434. return FuzzyBoolean.NO;
  435. }
  436. // Check the throws pattern
  437. if (subjectMatch && !throwsPattern.matches(aMethod.getExceptions(), world)) {
  438. return FuzzyBoolean.NO;
  439. }
  440. // '*' trivially matches everything, no need to check further
  441. if (!declaringType.isStar()) {
  442. if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) {
  443. return FuzzyBoolean.MAYBE;
  444. }
  445. }
  446. // '*' would match any return value
  447. if (!returnType.isStar()) {
  448. boolean b = returnType.isBangVoid();
  449. if (b) {
  450. String s = aMethod.getReturnType().getSignature();
  451. if (s.length() == 1 && s.charAt(0) == 'V') {
  452. // it is void, so not a match
  453. return FuzzyBoolean.NO;
  454. }
  455. } else {
  456. if (returnType.isVoid()) {
  457. String s = aMethod.getReturnType().getSignature();
  458. if (s.length() != 1 || s.charAt(0) != 'V') {
  459. // it is not void, so not a match
  460. return FuzzyBoolean.NO;
  461. }
  462. } else {
  463. if (!returnType.matchesStatically(aMethod.getReturnType().resolve(world))) {
  464. // looking bad, but there might be parameterization to consider...
  465. if (!returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) {
  466. // ok, it's bad.
  467. return FuzzyBoolean.MAYBE;
  468. }
  469. }
  470. }
  471. }
  472. }
  473. // The most simple case: pattern is (..) will match anything
  474. if (parameterTypes.size() == 1 && parameterTypes.get(0).isEllipsis()) {
  475. return FuzzyBoolean.YES;
  476. }
  477. if (!parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) {
  478. return FuzzyBoolean.NO;
  479. }
  480. // OPTIMIZE both resolution of these types and their annotations should be deferred - just pass down a world and do it lower
  481. // down
  482. // ResolvedType[] resolvedParameters = world.resolve(aMethod.getParameterTypes());
  483. ResolvableTypeList rtl = new ResolvableTypeList(world, aMethod.getParameterTypes());
  484. // Only fetch the parameter annotations if the pointcut is going to be matching on them
  485. ResolvedType[][] parameterAnnotationTypes = null;
  486. if (isMatchingParameterAnnotations()) {
  487. parameterAnnotationTypes = aMethod.getParameterAnnotationTypes();
  488. if (parameterAnnotationTypes != null && parameterAnnotationTypes.length == 0) {
  489. parameterAnnotationTypes = null;
  490. }
  491. }
  492. if (!parameterTypes.matches(rtl, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
  493. // It could still be a match based on the generic sig parameter types of a parameterized type
  494. if (!parameterTypes.matches(new ResolvableTypeList(world, aMethod.getGenericParameterTypes()), TypePattern.STATIC,
  495. parameterAnnotationTypes).alwaysTrue()) {
  496. return FuzzyBoolean.MAYBE;
  497. // It could STILL be a match based on the erasure of the parameter types??
  498. // to be determined via test cases...
  499. }
  500. }
  501. // check that varargs specifications match
  502. if (!matchesVarArgs(aMethod, world)) {
  503. return FuzzyBoolean.MAYBE;
  504. }
  505. // passed all the guards..
  506. return FuzzyBoolean.YES;
  507. }
  508. /**
  509. * Determine if any pattern in the parameter type pattern list is attempting to match on parameter annotations.
  510. *
  511. * @return true if a parameter type pattern wants to match on a parameter annotation
  512. */
  513. private boolean isMatchingParameterAnnotations() {
  514. if ((bits & CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING) == 0) {
  515. bits |= CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING;
  516. for (int tp = 0, max = parameterTypes.size(); tp < max; tp++) {
  517. TypePattern typePattern = parameterTypes.get(tp);
  518. if (isParameterAnnotationMatching(typePattern)) {
  519. bits |= PARAMETER_ANNOTATION_MATCHING;
  520. }
  521. }
  522. }
  523. return (bits & PARAMETER_ANNOTATION_MATCHING) != 0;
  524. }
  525. /**
  526. * Walk the simple structure of a type pattern and determine if any leaf node is involved in parameter annotation matching.
  527. */
  528. private boolean isParameterAnnotationMatching(TypePattern tp) {
  529. if (tp instanceof OrTypePattern) {
  530. OrTypePattern orAtp = (OrTypePattern) tp;
  531. return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
  532. } else if (tp instanceof AndTypePattern) {
  533. AndTypePattern andAtp = (AndTypePattern) tp;
  534. return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
  535. } else if (tp instanceof NotTypePattern) {
  536. NotTypePattern notAtp = (NotTypePattern) tp;
  537. return (isParameterAnnotationMatching(notAtp.getNegatedPattern()));
  538. } else {
  539. AnnotationTypePattern atp = tp.getAnnotationPattern();
  540. return isParameterAnnotationMatching(atp);
  541. }
  542. }
  543. private boolean isParameterAnnotationMatching(AnnotationTypePattern tp) {
  544. if (tp instanceof OrAnnotationTypePattern) {
  545. OrAnnotationTypePattern orAtp = (OrAnnotationTypePattern) tp;
  546. return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
  547. } else if (tp instanceof AndAnnotationTypePattern) {
  548. AndAnnotationTypePattern andAtp = (AndAnnotationTypePattern) tp;
  549. return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
  550. } else if (tp instanceof NotAnnotationTypePattern) {
  551. NotAnnotationTypePattern notAtp = (NotAnnotationTypePattern) tp;
  552. return (isParameterAnnotationMatching(notAtp.negatedPattern));
  553. } else {
  554. return tp.isForParameterAnnotationMatch();
  555. }
  556. }
  557. /**
  558. * match on declaring type, parameter types, throws types
  559. */
  560. private FuzzyBoolean matchesExactlyConstructor(JoinPointSignature aConstructor, World world) {
  561. if (!declaringType.matchesStatically(aConstructor.getDeclaringType().resolve(world))) {
  562. return FuzzyBoolean.NO;
  563. }
  564. if (!parameterTypes.canMatchSignatureWithNParameters(aConstructor.getParameterTypes().length)) {
  565. return FuzzyBoolean.NO;
  566. }
  567. ResolvedType[] resolvedParameters = world.resolve(aConstructor.getParameterTypes());
  568. ResolvedType[][] parameterAnnotationTypes = aConstructor.getParameterAnnotationTypes();
  569. if (parameterAnnotationTypes == null || parameterAnnotationTypes.length == 0) {
  570. parameterAnnotationTypes = null;
  571. }
  572. if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
  573. // It could still be a match based on the generic sig parameter types of a parameterized type
  574. if (!parameterTypes.matches(world.resolve(aConstructor.getGenericParameterTypes()), TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
  575. return FuzzyBoolean.MAYBE;
  576. // It could STILL be a match based on the erasure of the parameter types??
  577. // to be determined via test cases...
  578. }
  579. }
  580. // check that varargs specifications match
  581. if (!matchesVarArgs(aConstructor, world)) {
  582. return FuzzyBoolean.NO;
  583. }
  584. // Check the throws pattern
  585. if (!throwsPattern.matches(aConstructor.getExceptions(), world)) {
  586. return FuzzyBoolean.NO;
  587. }
  588. // passed all the guards..
  589. return FuzzyBoolean.YES;
  590. }
  591. /**
  592. * We've matched against this method or constructor so far, but without considering varargs (which has been matched as a simple
  593. * array thus far). Now we do the additional checks to see if the parties agree on whether the last parameter is varargs or a
  594. * straight array.
  595. */
  596. private boolean matchesVarArgs(JoinPointSignature aMethodOrConstructor, World inAWorld) {
  597. if (parameterTypes.size() == 0) {
  598. return true;
  599. }
  600. TypePattern lastPattern = parameterTypes.get(parameterTypes.size() - 1);
  601. boolean canMatchVarArgsSignature = lastPattern.isStar() || lastPattern.isVarArgs() || (lastPattern == TypePattern.ELLIPSIS);
  602. if (aMethodOrConstructor.isVarargsMethod()) {
  603. // we have at least one parameter in the pattern list, and the method has a varargs signature
  604. if (!canMatchVarArgsSignature) {
  605. // XXX - Ideally the shadow would be included in the msg but we don't know it...
  606. inAWorld.getLint().cantMatchArrayTypeOnVarargs.signal(aMethodOrConstructor.toString(), getSourceLocation());
  607. return false;
  608. }
  609. } else {
  610. // the method ends with an array type, check that we don't *require* a varargs
  611. if (lastPattern.isVarArgs()) {
  612. return false;
  613. }
  614. }
  615. return true;
  616. }
  617. private FuzzyBoolean matchesAnnotations(ResolvedMember member, World world) {
  618. if (member == null) {
  619. // world.getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
  620. return FuzzyBoolean.NO;
  621. }
  622. annotationPattern.resolve(world);
  623. // optimization before we go digging around for annotations on ITDs
  624. if (annotationPattern instanceof AnyAnnotationTypePattern) {
  625. return FuzzyBoolean.YES;
  626. }
  627. // fake members represent ITD'd fields - for their annotations we should go and look up the
  628. // relevant member in the original aspect
  629. if (member.isAnnotatedElsewhere() && member.getKind() == Member.FIELD) {
  630. // FIXME asc duplicate of code in AnnotationPointcut.matchInternal()? same fixmes apply here.
  631. // ResolvedMember [] mems = member.getDeclaringType().resolve(world).getDeclaredFields(); // FIXME asc should include
  632. // supers with getInterTypeMungersIncludingSupers?
  633. List<ConcreteTypeMunger> mungers = member.getDeclaringType().resolve(world).getInterTypeMungers();
  634. for (ConcreteTypeMunger typeMunger : mungers) {
  635. if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
  636. ResolvedMember fakerm = typeMunger.getSignature();
  637. ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
  638. ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
  639. if (fakerm.equals(member)) {
  640. member = rmm;
  641. }
  642. }
  643. }
  644. }
  645. if (annotationPattern.matches(member).alwaysTrue()) {
  646. return FuzzyBoolean.YES;
  647. } else {
  648. // do NOT look at ancestor members... only the subject can have an annotation match
  649. // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
  650. return FuzzyBoolean.NO;
  651. }
  652. }
  653. private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
  654. ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
  655. for (ResolvedMember member : decMethods) {
  656. if (member.equals(ajcMethod)) {
  657. return member;
  658. }
  659. }
  660. return null;
  661. }
  662. public boolean declaringTypeMatchAllowingForCovariance(Member member, UnresolvedType shadowDeclaringType, World world,
  663. TypePattern returnTypePattern, ResolvedType sigReturn) {
  664. ResolvedType onType = shadowDeclaringType.resolve(world);
  665. // fastmatch
  666. if (declaringType.matchesStatically(onType) && returnTypePattern.matchesStatically(sigReturn)) {
  667. return true;
  668. }
  669. Collection<ResolvedType> declaringTypes = member.getDeclaringTypes(world);
  670. boolean checkReturnType = true;
  671. // XXX Possible enhancement? Doesn't seem to speed things up
  672. // if (returnTypePattern.isStar()) {
  673. // if (returnTypePattern instanceof WildTypePattern) {
  674. // if (((WildTypePattern)returnTypePattern).getDimensions()==0) checkReturnType = false;
  675. // }
  676. // }
  677. // Sometimes that list includes types that don't explicitly declare the member we are after -
  678. // they are on the list because their supertype is on the list, that's why we use
  679. // lookupMethod rather than lookupMemberNoSupers()
  680. for (ResolvedType type : declaringTypes) {
  681. if (declaringType.matchesStatically(type)) {
  682. if (!checkReturnType) {
  683. return true;
  684. }
  685. ResolvedMember rm = type.lookupMethod(member);
  686. if (rm == null) {
  687. rm = type.lookupMethodInITDs(member); // It must be in here, or we have *real* problems
  688. }
  689. if (rm == null) {
  690. continue; // might be currently looking at the generic type and we need to continue searching in case we hit a
  691. }
  692. // parameterized version of this same type...
  693. UnresolvedType returnTypeX = rm.getReturnType();
  694. ResolvedType returnType = returnTypeX.resolve(world);
  695. if (returnTypePattern.matchesStatically(returnType)) {
  696. return true;
  697. }
  698. }
  699. }
  700. return false;
  701. }
  702. // private Collection getDeclaringTypes(Signature sig) {
  703. // List l = new ArrayList();
  704. // Class onType = sig.getDeclaringType();
  705. // String memberName = sig.getName();
  706. // if (sig instanceof FieldSignature) {
  707. // Class fieldType = ((FieldSignature)sig).getFieldType();
  708. // Class superType = onType;
  709. // while(superType != null) {
  710. // try {
  711. // Field f = (superType.getDeclaredField(memberName));
  712. // if (f.getType() == fieldType) {
  713. // l.add(superType);
  714. // }
  715. // } catch (NoSuchFieldException nsf) {}
  716. // superType = superType.getSuperclass();
  717. // }
  718. // } else if (sig instanceof MethodSignature) {
  719. // Class[] paramTypes = ((MethodSignature)sig).getParameterTypes();
  720. // Class superType = onType;
  721. // while(superType != null) {
  722. // try {
  723. // superType.getDeclaredMethod(memberName,paramTypes);
  724. // l.add(superType);
  725. // } catch (NoSuchMethodException nsm) {}
  726. // superType = superType.getSuperclass();
  727. // }
  728. // }
  729. // return l;
  730. // }
  731. public NamePattern getName() {
  732. return name;
  733. }
  734. public TypePattern getDeclaringType() {
  735. return declaringType;
  736. }
  737. public MemberKind getKind() {
  738. return kind;
  739. }
  740. @Override
  741. public String toString() {
  742. StringBuilder buf = new StringBuilder();
  743. if (annotationPattern != AnnotationTypePattern.ANY) {
  744. buf.append(annotationPattern.toString());
  745. buf.append(' ');
  746. }
  747. if (modifiers != ModifiersPattern.ANY) {
  748. buf.append(modifiers.toString());
  749. buf.append(' ');
  750. }
  751. if (kind == Member.STATIC_INITIALIZATION) {
  752. buf.append(declaringType.toString());
  753. buf.append(".<clinit>()");// FIXME AV - bad, cannot be parsed again
  754. } else if (kind == Member.HANDLER) {
  755. buf.append("handler(");
  756. buf.append(parameterTypes.get(0));
  757. buf.append(")");
  758. } else {
  759. if (!(kind == Member.CONSTRUCTOR)) {
  760. buf.append(returnType.toString());
  761. buf.append(' ');
  762. }
  763. if (declaringType != TypePattern.ANY) {
  764. buf.append(declaringType.toString());
  765. buf.append('.');
  766. }
  767. if (kind == Member.CONSTRUCTOR) {
  768. buf.append("new");
  769. } else {
  770. buf.append(name.toString());
  771. }
  772. if (kind == Member.METHOD || kind == Member.CONSTRUCTOR) {
  773. buf.append(parameterTypes.toString());
  774. }
  775. // FIXME AV - throws is not printed here, weird
  776. }
  777. return buf.toString();
  778. }
  779. @Override
  780. public boolean equals(Object other) {
  781. if (!(other instanceof SignaturePattern)) {
  782. return false;
  783. }
  784. SignaturePattern o = (SignaturePattern) other;
  785. return o.kind.equals(this.kind) && o.modifiers.equals(this.modifiers) && o.returnType.equals(this.returnType)
  786. && o.declaringType.equals(this.declaringType) && o.name.equals(this.name)
  787. && o.parameterTypes.equals(this.parameterTypes) && o.throwsPattern.equals(this.throwsPattern)
  788. && o.annotationPattern.equals(this.annotationPattern);
  789. }
  790. @Override
  791. public int hashCode() {
  792. if (hashcode == -1) {
  793. hashcode = 17;
  794. hashcode = 37 * hashcode + kind.hashCode();
  795. hashcode = 37 * hashcode + modifiers.hashCode();
  796. hashcode = 37 * hashcode + returnType.hashCode();
  797. hashcode = 37 * hashcode + declaringType.hashCode();
  798. hashcode = 37 * hashcode + name.hashCode();
  799. hashcode = 37 * hashcode + parameterTypes.hashCode();
  800. hashcode = 37 * hashcode + throwsPattern.hashCode();
  801. hashcode = 37 * hashcode + annotationPattern.hashCode();
  802. }
  803. return hashcode;
  804. }
  805. @Override
  806. public void write(CompressingDataOutputStream s) throws IOException {
  807. kind.write(s);
  808. modifiers.write(s);
  809. returnType.write(s);
  810. declaringType.write(s);
  811. name.write(s);
  812. parameterTypes.write(s);
  813. throwsPattern.write(s);
  814. annotationPattern.write(s);
  815. writeLocation(s);
  816. }
  817. public static SignaturePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  818. // ISignaturePattern kind should already have been read by the time this read is entered
  819. MemberKind kind = MemberKind.read(s);
  820. ModifiersPattern modifiers = ModifiersPattern.read(s);
  821. TypePattern returnType = TypePattern.read(s, context);
  822. TypePattern declaringType = TypePattern.read(s, context);
  823. NamePattern name = NamePattern.read(s);
  824. TypePatternList parameterTypes = TypePatternList.read(s, context);
  825. ThrowsPattern throwsPattern = ThrowsPattern.read(s, context);
  826. AnnotationTypePattern annotationPattern = AnnotationTypePattern.ANY;
  827. if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
  828. annotationPattern = AnnotationTypePattern.read(s, context);
  829. }
  830. SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
  831. throwsPattern, annotationPattern);
  832. ret.readLocation(context, s);
  833. return ret;
  834. }
  835. /**
  836. * @return
  837. */
  838. public ModifiersPattern getModifiers() {
  839. return modifiers;
  840. }
  841. /**
  842. * @return
  843. */
  844. public TypePatternList getParameterTypes() {
  845. return parameterTypes;
  846. }
  847. /**
  848. * @return
  849. */
  850. public TypePattern getReturnType() {
  851. return returnType;
  852. }
  853. /**
  854. * @return
  855. */
  856. public ThrowsPattern getThrowsPattern() {
  857. return throwsPattern;
  858. }
  859. /**
  860. * return true if last argument in params is an Object[] but the modifiers say this method was declared with varargs
  861. * (Object...). We shouldn't be matching if this is the case.
  862. */
  863. // private boolean matchedArrayAgainstVarArgs(TypePatternList params,int modifiers) {
  864. // if (params.size()>0 && (modifiers & Constants.ACC_VARARGS)!=0) {
  865. // // we have at least one parameter in the pattern list, and the method has a varargs signature
  866. // TypePattern lastPattern = params.get(params.size()-1);
  867. // if (lastPattern.isArray() && !lastPattern.isVarArgs) return true;
  868. // }
  869. // return false;
  870. // }
  871. public AnnotationTypePattern getAnnotationPattern() {
  872. return annotationPattern;
  873. }
  874. @Override
  875. public boolean isStarAnnotation() {
  876. return annotationPattern == AnnotationTypePattern.ANY;
  877. }
  878. @Override
  879. public Object accept(PatternNodeVisitor visitor, Object data) {
  880. return visitor.visit(this, data);
  881. }
  882. public Object traverse(PatternNodeVisitor visitor, Object data) {
  883. Object ret = accept(visitor, data);
  884. if (this.annotationPattern != null)
  885. this.annotationPattern.traverse(visitor, ret);
  886. if (this.returnType != null)
  887. this.returnType.traverse(visitor, ret);
  888. if (this.declaringType != null)
  889. this.declaringType.traverse(visitor, ret);
  890. if (this.name != null)
  891. this.name.traverse(visitor, ret);
  892. if (this.parameterTypes != null)
  893. this.parameterTypes.traverse(visitor, ret);
  894. if (this.throwsPattern != null)
  895. this.throwsPattern.traverse(visitor, ret);
  896. return ret;
  897. }
  898. public boolean isExactDeclaringTypePattern() {
  899. return isExactDeclaringTypePattern;
  900. }
  901. @Override
  902. public boolean isMatchOnAnyName() {
  903. return getName().isAny();
  904. }
  905. @Override
  906. public List<ExactTypePattern> getExactDeclaringTypes() {
  907. if (declaringType instanceof ExactTypePattern) {
  908. List<ExactTypePattern> l = new ArrayList<>();
  909. l.add((ExactTypePattern) declaringType);
  910. return l;
  911. } else {
  912. return Collections.emptyList();
  913. }
  914. }
  915. @Override
  916. public boolean couldEverMatch(ResolvedType type) {
  917. return declaringType.matches(type, TypePattern.STATIC).maybeTrue();
  918. }
  919. }