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.

DeclareAnnotation.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /* *******************************************************************
  2. * Copyright (c) 2005 IBM Corporation
  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. * Adrian Colyer initial implementation
  11. * Andy Clement got it working
  12. * ******************************************************************/
  13. package org.aspectj.weaver.patterns;
  14. import java.io.IOException;
  15. import java.util.ArrayList;
  16. import java.util.Iterator;
  17. import java.util.List;
  18. import java.util.Map;
  19. import org.aspectj.bridge.MessageUtil;
  20. import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
  21. import org.aspectj.weaver.AnnotationAJ;
  22. import org.aspectj.weaver.CompressingDataOutputStream;
  23. import org.aspectj.weaver.ISourceContext;
  24. import org.aspectj.weaver.ResolvedMember;
  25. import org.aspectj.weaver.ResolvedType;
  26. import org.aspectj.weaver.UnresolvedType;
  27. import org.aspectj.weaver.VersionedDataInputStream;
  28. import org.aspectj.weaver.WeaverMessages;
  29. import org.aspectj.weaver.World;
  30. /**
  31. * Represents a declare annotation statement, one of atField, atMethod, atConstructor or atType.
  32. *
  33. * @author Andy Clement
  34. */
  35. public class DeclareAnnotation extends Declare {
  36. public static final Kind AT_TYPE = new Kind(1, "type");
  37. public static final Kind AT_FIELD = new Kind(2, "field");
  38. public static final Kind AT_METHOD = new Kind(3, "method");
  39. public static final Kind AT_CONSTRUCTOR = new Kind(4, "constructor");
  40. public static final Kind AT_REMOVE_FROM_FIELD = new Kind(5, "removeFromField");
  41. private static final String AJC_DECLARE_ANNOTATION = "Lorg/aspectj/internal/lang/annotation/ajcDeclareAnnotation;";
  42. private Kind kind;
  43. // for declare @type
  44. private TypePattern typePattern;
  45. // for declare @field,@method,@constructor
  46. private ISignaturePattern signaturePattern;
  47. private ResolvedType containingAspect;
  48. private List<String> annotationMethods;
  49. private List<String> annotationStrings;
  50. private AnnotationAJ annotation; // discovered when required
  51. private ResolvedType annotationType; // discovered when required
  52. // not serialized:
  53. private int annotationStart;
  54. private int annotationEnd;
  55. /**
  56. * Constructor for declare atType.
  57. */
  58. public DeclareAnnotation(Kind kind, TypePattern typePattern) {
  59. this.typePattern = typePattern;
  60. this.kind = kind;
  61. init();
  62. }
  63. /**
  64. * Constructor for declare atMethod/atField/atConstructor.
  65. */
  66. public DeclareAnnotation(Kind kind, ISignaturePattern sigPattern) {
  67. this.signaturePattern = sigPattern;
  68. this.kind = kind;
  69. init();
  70. }
  71. private void init() {
  72. this.annotationMethods = new ArrayList<>();
  73. annotationMethods.add("unknown");
  74. this.annotationStrings = new ArrayList<>();
  75. annotationStrings.add("@<annotation>");
  76. }
  77. /**
  78. * Returns the string, useful before the real annotation has been resolved
  79. */
  80. public String getAnnotationString() {
  81. return annotationStrings.get(0);
  82. }
  83. public boolean isExactPattern() {
  84. return typePattern instanceof ExactTypePattern;
  85. }
  86. public String getAnnotationMethod() {
  87. return annotationMethods.get(0);
  88. }
  89. @Override
  90. public String toString() {
  91. StringBuilder ret = new StringBuilder();
  92. ret.append("declare @");
  93. ret.append(kind);
  94. ret.append(" : ");
  95. ret.append(typePattern != null ? typePattern.toString() : signaturePattern.toString());
  96. ret.append(" : ");
  97. ret.append(annotationStrings.get(0));
  98. return ret.toString();
  99. }
  100. @Override
  101. public Object accept(PatternNodeVisitor visitor, Object data) {
  102. return visitor.visit(this, data);
  103. }
  104. @Override
  105. public void resolve(IScope scope) {
  106. if (!scope.getWorld().isInJava5Mode()) {
  107. String msg = null;
  108. if (kind == AT_TYPE) {
  109. msg = WeaverMessages.DECLARE_ATTYPE_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
  110. } else if (kind == AT_METHOD) {
  111. msg = WeaverMessages.DECLARE_ATMETHOD_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
  112. } else if (kind == AT_FIELD) {
  113. msg = WeaverMessages.DECLARE_ATFIELD_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
  114. } else if (kind == AT_CONSTRUCTOR) {
  115. msg = WeaverMessages.DECLARE_ATCONS_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
  116. }
  117. scope.message(MessageUtil.error(WeaverMessages.format(msg), getSourceLocation()));
  118. return;
  119. }
  120. if (typePattern != null) {
  121. typePattern = typePattern.resolveBindings(scope, Bindings.NONE, false, false);
  122. }
  123. if (signaturePattern != null) {
  124. signaturePattern = signaturePattern.resolveBindings(scope, Bindings.NONE);
  125. }
  126. this.containingAspect = scope.getEnclosingType();
  127. }
  128. @Override
  129. public Declare parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World w) {
  130. DeclareAnnotation ret;
  131. if (this.kind == AT_TYPE) {
  132. ret = new DeclareAnnotation(kind, this.typePattern.parameterizeWith(typeVariableBindingMap, w));
  133. } else {
  134. ret = new DeclareAnnotation(kind, this.signaturePattern.parameterizeWith(typeVariableBindingMap, w));
  135. }
  136. ret.annotationMethods = this.annotationMethods;
  137. ret.annotationStrings = this.annotationStrings;
  138. ret.annotation = this.annotation;
  139. ret.containingAspect = this.containingAspect;
  140. ret.copyLocationFrom(this);
  141. return ret;
  142. }
  143. @Override
  144. public boolean isAdviceLike() {
  145. return false;
  146. }
  147. public void setAnnotationString(String annotationString) {
  148. this.annotationStrings.set(0, annotationString);
  149. }
  150. public void setAnnotationLocation(int start, int end) {
  151. this.annotationStart = start;
  152. this.annotationEnd = end;
  153. }
  154. public int getAnnotationSourceStart() {
  155. return annotationStart;
  156. }
  157. public int getAnnotationSourceEnd() {
  158. return annotationEnd;
  159. }
  160. public void setAnnotationMethod(String methodName) {
  161. this.annotationMethods.set(0, methodName);
  162. }
  163. @Override
  164. public boolean equals(Object obj) {
  165. if (!(obj instanceof DeclareAnnotation)) {
  166. return false;
  167. }
  168. DeclareAnnotation other = (DeclareAnnotation) obj;
  169. if (!this.kind.equals(other.kind)) {
  170. return false;
  171. }
  172. if (!this.annotationStrings.get(0).equals(other.annotationStrings.get(0))) {
  173. return false;
  174. }
  175. if (!this.annotationMethods.get(0).equals(other.annotationMethods.get(0))) {
  176. return false;
  177. }
  178. if (this.typePattern != null) {
  179. if (!typePattern.equals(other.typePattern)) {
  180. return false;
  181. }
  182. }
  183. if (this.signaturePattern != null) {
  184. if (!signaturePattern.equals(other.signaturePattern)) {
  185. return false;
  186. }
  187. }
  188. return true;
  189. }
  190. @Override
  191. public int hashCode() {
  192. int result = 19;
  193. result = 37 * result + kind.hashCode();
  194. result = 37 * result + annotationStrings.get(0).hashCode();
  195. result = 37 * result + annotationMethods.get(0).hashCode();
  196. if (typePattern != null) {
  197. result = 37 * result + typePattern.hashCode();
  198. }
  199. if (signaturePattern != null) {
  200. result = 37 * result + signaturePattern.hashCode();
  201. }
  202. return result;
  203. }
  204. @Override
  205. public void write(CompressingDataOutputStream s) throws IOException {
  206. s.writeByte(Declare.ANNOTATION);
  207. if (kind.id == AT_FIELD.id && isRemover) {
  208. s.writeInt(AT_REMOVE_FROM_FIELD.id);
  209. } else {
  210. s.writeInt(kind.id);
  211. }
  212. int max = 0;
  213. s.writeByte(max = annotationStrings.size());
  214. for (int i = 0; i < max; i++) {
  215. s.writeUTF(annotationStrings.get(i));
  216. }
  217. s.writeByte(max = annotationMethods.size());
  218. for (int i = 0; i < max; i++) {
  219. s.writeUTF(annotationMethods.get(i));
  220. }
  221. if (typePattern != null) {
  222. typePattern.write(s);
  223. }
  224. if (signaturePattern != null) {
  225. AbstractSignaturePattern.writeCompoundSignaturePattern(s, signaturePattern);
  226. }
  227. writeLocation(s);
  228. }
  229. public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  230. DeclareAnnotation ret = null;
  231. boolean isRemover = false;
  232. int kind = s.readInt();
  233. if (kind == AT_REMOVE_FROM_FIELD.id) {
  234. kind = AT_FIELD.id;
  235. isRemover = true;
  236. }
  237. // old format was just a single string and method
  238. if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
  239. // int numAnnotationStrings =
  240. s.readByte();
  241. }
  242. String annotationString = s.readUTF();
  243. if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
  244. // int numAnnotationMethods =
  245. s.readByte();
  246. }
  247. String annotationMethod = s.readUTF();
  248. TypePattern tp = null;
  249. SignaturePattern sp = null;
  250. switch (kind) {
  251. case 1:
  252. tp = TypePattern.read(s, context);
  253. ret = new DeclareAnnotation(AT_TYPE, tp);
  254. break;
  255. case 2:
  256. if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
  257. ret = new DeclareAnnotation(AT_FIELD, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
  258. } else {
  259. sp = SignaturePattern.read(s, context);
  260. ret = new DeclareAnnotation(AT_FIELD, sp);
  261. }
  262. if (isRemover) {
  263. ret.setRemover(true);
  264. }
  265. break;
  266. case 3:
  267. if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
  268. ret = new DeclareAnnotation(AT_METHOD, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
  269. } else {
  270. sp = SignaturePattern.read(s, context);
  271. ret = new DeclareAnnotation(AT_METHOD, sp);
  272. }
  273. break;
  274. case 4:
  275. if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
  276. ret = new DeclareAnnotation(AT_CONSTRUCTOR, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
  277. } else {
  278. sp = SignaturePattern.read(s, context);
  279. ret = new DeclareAnnotation(AT_CONSTRUCTOR, sp);
  280. }
  281. break;
  282. }
  283. ret.setAnnotationString(annotationString);
  284. ret.setAnnotationMethod(annotationMethod);
  285. ret.readLocation(context, s);
  286. return ret;
  287. }
  288. /**
  289. * For declare atConstructor, atMethod, atField
  290. */
  291. public boolean matches(ResolvedMember resolvedmember, World world) {
  292. if (kind == AT_METHOD || kind == AT_CONSTRUCTOR) {
  293. if (resolvedmember != null && resolvedmember.getName().charAt(0) == '<') {
  294. // <clinit> or <init>
  295. if (kind == AT_METHOD) {
  296. return false;
  297. }
  298. }
  299. }
  300. return signaturePattern.matches(resolvedmember, world, false);
  301. }
  302. /**
  303. * For declare atType.
  304. */
  305. public boolean matches(ResolvedType type) {
  306. if (!typePattern.matchesStatically(type)) {
  307. return false;
  308. }
  309. if (type.getWorld().getLint().typeNotExposedToWeaver.isEnabled() && !type.isExposedToWeaver()) {
  310. type.getWorld().getLint().typeNotExposedToWeaver.signal(type.getName(), getSourceLocation());
  311. }
  312. return true;
  313. }
  314. public void setAspect(ResolvedType typeX) {
  315. containingAspect = typeX;
  316. }
  317. public UnresolvedType getAspect() {
  318. return containingAspect;
  319. }
  320. public void copyAnnotationTo(ResolvedType onType) {
  321. ensureAnnotationDiscovered();
  322. if (annotation == null)
  323. return;
  324. if (!onType.hasAnnotation(annotation.getType())) {
  325. onType.addAnnotation(annotation);
  326. }
  327. }
  328. /**
  329. * @return declared annotation; can be null for annotations with SOURCE retention, which of course are not present in
  330. * the byte code
  331. */
  332. public AnnotationAJ getAnnotation() {
  333. ensureAnnotationDiscovered();
  334. return annotation;
  335. }
  336. /**
  337. * The annotation specified in the declare @type is stored against a simple method of the form "ajc$declare_<NN>",
  338. * this method finds that method and retrieves the annotation.
  339. * <p>
  340. * Caveat: Nothing will be found for annotations with SOURCE retention, which of course are not present in the byte
  341. * code.
  342. */
  343. private void ensureAnnotationDiscovered() {
  344. if (annotation != null)
  345. return;
  346. String annotationMethod = annotationMethods.get(0);
  347. for (Iterator<ResolvedMember> iter = containingAspect.getMethods(true, true); iter.hasNext();) {
  348. ResolvedMember member = iter.next();
  349. if (!member.getName().equals(annotationMethod))
  350. continue;
  351. AnnotationAJ[] annos = member.getAnnotations();
  352. // If weaving broken code, annos can be null or empty
  353. if (annos == null || annos.length == 0)
  354. return;
  355. int idx = 0;
  356. if (annos[0].getType().getSignature().equals(AJC_DECLARE_ANNOTATION)) {
  357. // @ajcDeclareAnnotation marker annotations should always come in pairs with the actual declared annotations.
  358. // If the second annotation is not found, it means that it has SOURCE retention and the annotation declaration
  359. // is to be ignored.
  360. if (annos.length < 2)
  361. break;
  362. idx = 1;
  363. }
  364. annotation = annos[idx];
  365. break;
  366. }
  367. }
  368. public TypePattern getTypePattern() {
  369. return typePattern;
  370. }
  371. public ISignaturePattern getSignaturePattern() {
  372. return signaturePattern;
  373. }
  374. public boolean isStarredAnnotationPattern() {
  375. if (typePattern != null) {
  376. return typePattern.isStarAnnotation();
  377. } else {
  378. return signaturePattern.isStarAnnotation();
  379. }
  380. }
  381. public Kind getKind() {
  382. return kind;
  383. }
  384. public boolean isDeclareAtConstuctor() {
  385. return kind.equals(AT_CONSTRUCTOR);
  386. }
  387. public boolean isDeclareAtMethod() {
  388. return kind.equals(AT_METHOD);
  389. }
  390. public boolean isDeclareAtType() {
  391. return kind.equals(AT_TYPE);
  392. }
  393. public boolean isDeclareAtField() {
  394. return kind.equals(AT_FIELD);
  395. }
  396. /**
  397. * @return the type of the annotation; can be null for annotations with SOURCE retention, which of course are not
  398. * present in the byte code
  399. */
  400. public ResolvedType getAnnotationType() {
  401. if (annotationType != null)
  402. return annotationType;
  403. String annotationMethod = annotationMethods.get(0);
  404. for (Iterator<ResolvedMember> iter = containingAspect.getMethods(true, true); iter.hasNext(); ) {
  405. ResolvedMember member = iter.next();
  406. if (!member.getName().equals(annotationMethod))
  407. continue;
  408. ResolvedType[] annoTypes = member.getAnnotationTypes();
  409. // If weaving broken code, annoTypes can be null or empty
  410. if (annoTypes == null || annoTypes.length == 0)
  411. return null;
  412. int idx = 0;
  413. if (annoTypes[0].getSignature().equals(AJC_DECLARE_ANNOTATION)) {
  414. // @ajcDeclareAnnotation marker annotations should always come in pairs with the actual declared annotations.
  415. // If the second annotation is not found, it means that it has SOURCE retention and the annotation declaration
  416. // is to be ignored.
  417. if (annoTypes.length < 2)
  418. break;
  419. idx = 1;
  420. }
  421. annotationType = annoTypes[idx];
  422. break;
  423. }
  424. return annotationType;
  425. }
  426. /**
  427. * @return true if the annotation specified is allowed on a field
  428. */
  429. public boolean isAnnotationAllowedOnField() {
  430. ensureAnnotationDiscovered();
  431. return annotation != null && annotation.allowedOnField();
  432. }
  433. public String getPatternAsString() {
  434. if (signaturePattern != null) {
  435. return signaturePattern.toString();
  436. }
  437. if (typePattern != null) {
  438. return typePattern.toString();
  439. }
  440. return "DONT KNOW";
  441. }
  442. /**
  443. * Return true if this declare annotation could ever match something in the specified type - only really able to make
  444. * intelligent decision if a type was specified in the sig/type pattern signature.
  445. */
  446. public boolean couldEverMatch(ResolvedType type) {
  447. // Haven't implemented variant for typePattern (doesn't seem worth it!)
  448. // BUGWARNING This test might not be sufficient for funny cases relating
  449. // to interfaces and the use of '+' - but it seems really important to
  450. // do something here so we don't iterate over all fields and all methods
  451. // in all types exposed to the weaver! So look out for bugs here and
  452. // we can update the test as appropriate.
  453. if (signaturePattern != null) {
  454. return signaturePattern.couldEverMatch(type);
  455. }
  456. return true;
  457. }
  458. /**
  459. * Provide a name suffix so that we can tell the different declare annotations forms apart in the AjProblemReporter
  460. */
  461. @Override
  462. public String getNameSuffix() {
  463. return getKind().toString();
  464. }
  465. /**
  466. * Captures type of declare annotation (method/type/field/constructor)
  467. */
  468. public static class Kind {
  469. private final int id;
  470. private String s;
  471. private Kind(int n, String name) {
  472. id = n;
  473. s = name;
  474. }
  475. @Override
  476. public int hashCode() {
  477. return (19 + 37 * id);
  478. }
  479. @Override
  480. public boolean equals(Object obj) {
  481. if (!(obj instanceof Kind)) {
  482. return false;
  483. }
  484. Kind other = (Kind) obj;
  485. return other.id == id;
  486. }
  487. @Override
  488. public String toString() {
  489. return "at_" + s;
  490. }
  491. }
  492. boolean isRemover = false;
  493. public void setRemover(boolean b) {
  494. isRemover = b;
  495. }
  496. public boolean isRemover() {
  497. return isRemover;
  498. }
  499. }