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.

CrosscuttingMembersSet.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /* *******************************************************************
  2. * Copyright (c) 2002-2009 Contributors
  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;
  13. import java.io.IOException;
  14. import java.util.ArrayList;
  15. import java.util.Collections;
  16. import java.util.HashMap;
  17. import java.util.HashSet;
  18. import java.util.LinkedHashSet;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Set;
  22. import org.aspectj.bridge.IMessage;
  23. import org.aspectj.bridge.MessageUtil;
  24. import org.aspectj.weaver.patterns.Declare;
  25. import org.aspectj.weaver.patterns.DeclareAnnotation;
  26. import org.aspectj.weaver.patterns.DeclareParents;
  27. import org.aspectj.weaver.patterns.DeclareSoft;
  28. import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
  29. import org.aspectj.weaver.patterns.IVerificationRequired;
  30. /**
  31. * This holds on to all CrosscuttingMembers for a world. It handles management of change.
  32. *
  33. * @author Jim Hugunin
  34. * @author Andy Clement
  35. */
  36. public class CrosscuttingMembersSet {
  37. private transient World world;
  38. // FIXME AV - ? we may need a sequencedHashMap there to ensure source based precedence for @AJ advice
  39. private final Map<ResolvedType, CrosscuttingMembers> members = new HashMap<>();
  40. // List of things to be verified once the type system is 'complete'
  41. private transient List<IVerificationRequired> verificationList = null;
  42. private List<ShadowMunger> shadowMungers = null;
  43. private List<ConcreteTypeMunger> typeMungers = null;
  44. private List<ConcreteTypeMunger> lateTypeMungers = null;
  45. private List<DeclareSoft> declareSofts = null;
  46. private List<DeclareParents> declareParents = null;
  47. private List<DeclareAnnotation> declareAnnotationOnTypes = null;
  48. private List<DeclareAnnotation> declareAnnotationOnFields = null;
  49. private List<DeclareAnnotation> declareAnnotationOnMethods = null; // includes constructors
  50. private List<DeclareTypeErrorOrWarning> declareTypeEows = null;
  51. private List<Declare> declareDominates = null;
  52. private boolean changedSinceLastReset = false;
  53. public CrosscuttingMembersSet(World world) {
  54. this.world = world;
  55. }
  56. public boolean addOrReplaceAspect(ResolvedType aspectType) {
  57. return addOrReplaceAspect(aspectType, true);
  58. }
  59. /**
  60. * Check if any parent aspects of the supplied aspect have unresolved dependencies (and so
  61. * should cause this aspect to be turned off).
  62. * @param aspectType the aspect whose parents should be checked
  63. * @return true if this aspect should be excluded because of a parents' missing dependencies
  64. */
  65. private boolean excludeDueToParentAspectHavingUnresolvedDependency(ResolvedType aspectType) {
  66. ResolvedType parent = aspectType.getSuperclass();
  67. boolean excludeDueToParent = false;
  68. while (parent != null) {
  69. if (parent.isAspect() && parent.isAbstract() && world.hasUnsatisfiedDependency(parent)) {
  70. if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
  71. world.getMessageHandler().handleMessage(
  72. MessageUtil.info("deactivating aspect '" + aspectType.getName() + "' as the parent aspect '"+parent.getName()+
  73. "' has unsatisfied dependencies"));
  74. }
  75. excludeDueToParent = true;
  76. }
  77. parent = parent.getSuperclass();
  78. }
  79. return excludeDueToParent;
  80. }
  81. /**
  82. * @return whether or not that was a change to the global signature XXX for efficiency we will need a richer representation than
  83. * this
  84. */
  85. public boolean addOrReplaceAspect(ResolvedType aspectType, boolean inWeavingPhase) {
  86. if (!world.isAspectIncluded(aspectType)) {
  87. return false;
  88. }
  89. if (world.hasUnsatisfiedDependency(aspectType)) {
  90. return false;
  91. }
  92. // Abstract super aspects might have unsatisfied dependencies
  93. if (excludeDueToParentAspectHavingUnresolvedDependency(aspectType)) {
  94. return false;
  95. }
  96. boolean change = false;
  97. CrosscuttingMembers xcut = members.get(aspectType);
  98. if (xcut == null) {
  99. members.put(aspectType, aspectType.collectCrosscuttingMembers(inWeavingPhase));
  100. clearCaches();
  101. change = true;
  102. } else {
  103. if (xcut.replaceWith(aspectType.collectCrosscuttingMembers(inWeavingPhase), inWeavingPhase)) {
  104. clearCaches();
  105. change = true;
  106. } else {
  107. if (inWeavingPhase) {
  108. // bug 134541 - even though we haven't changed we may have updated the
  109. // sourcelocation for the shadowMunger which we need to pick up
  110. shadowMungers = null;
  111. }
  112. change = false;
  113. }
  114. }
  115. if (aspectType.isAbstract()) {
  116. // we might have sub-aspects that need to re-collect their crosscutting members from us
  117. boolean ancestorChange = addOrReplaceDescendantsOf(aspectType, inWeavingPhase);
  118. change = change || ancestorChange;
  119. }
  120. changedSinceLastReset = changedSinceLastReset || change;
  121. return change;
  122. }
  123. private boolean addOrReplaceDescendantsOf(ResolvedType aspectType, boolean inWeavePhase) {
  124. // System.err.println("Looking at descendants of "+aspectType.getName());
  125. Set<ResolvedType> knownAspects = members.keySet();
  126. Set<ResolvedType> toBeReplaced = new HashSet<>();
  127. for (ResolvedType candidateDescendant : knownAspects) {
  128. // allowMissing = true - if something is missing, it really probably is not a descendant
  129. if ((candidateDescendant != aspectType) && (aspectType.isAssignableFrom(candidateDescendant, true))) {
  130. toBeReplaced.add(candidateDescendant);
  131. }
  132. }
  133. boolean change = false;
  134. for (ResolvedType next : toBeReplaced) {
  135. boolean thisChange = addOrReplaceAspect(next, inWeavePhase);
  136. change = change || thisChange;
  137. }
  138. return change;
  139. }
  140. public void addAdviceLikeDeclares(ResolvedType aspectType) {
  141. if (!members.containsKey(aspectType)) {
  142. return;
  143. }
  144. CrosscuttingMembers xcut = members.get(aspectType);
  145. xcut.addDeclares(aspectType.collectDeclares(true));
  146. }
  147. public boolean deleteAspect(UnresolvedType aspectType) {
  148. boolean isAspect = members.remove(aspectType) != null;
  149. clearCaches();
  150. return isAspect;
  151. }
  152. public boolean containsAspect(UnresolvedType aspectType) {
  153. return members.containsKey(aspectType);
  154. }
  155. // XXX only for testing
  156. public void addFixedCrosscuttingMembers(ResolvedType aspectType) {
  157. members.put(aspectType, aspectType.crosscuttingMembers);
  158. clearCaches();
  159. }
  160. private void clearCaches() {
  161. shadowMungers = null;
  162. typeMungers = null;
  163. lateTypeMungers = null;
  164. declareSofts = null;
  165. declareParents = null;
  166. declareAnnotationOnFields = null;
  167. declareAnnotationOnMethods = null;
  168. declareAnnotationOnTypes = null;
  169. declareDominates = null;
  170. }
  171. public List<ShadowMunger> getShadowMungers() {
  172. if (shadowMungers == null) {
  173. List<ShadowMunger> ret = new ArrayList<>();
  174. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  175. ret.addAll(crosscuttingMembers.getShadowMungers());
  176. }
  177. shadowMungers = ret;
  178. }
  179. return shadowMungers;
  180. }
  181. public List<ConcreteTypeMunger> getTypeMungers() {
  182. if (typeMungers == null) {
  183. List<ConcreteTypeMunger> ret = new ArrayList<>();
  184. for (CrosscuttingMembers xmembers : members.values()) {
  185. // With 1.6.9 there is a change that enables use of more optimal accessors (accessors for private fields).
  186. // Here is where we determine if two aspects are asking for access to the same field. If they are
  187. // and
  188. // In the new style multiple aspects can share the same privileged accessors, so here we check if
  189. // two aspects are asking for access to the same field. If they are then we don't add a duplicate
  190. // accessor.
  191. for (ConcreteTypeMunger mungerToAdd : xmembers.getTypeMungers()) {
  192. ResolvedTypeMunger resolvedMungerToAdd = mungerToAdd.getMunger();
  193. if (isNewStylePrivilegedAccessMunger(resolvedMungerToAdd)) {
  194. String newFieldName = resolvedMungerToAdd.getSignature().getName();
  195. boolean alreadyExists = false;
  196. for (ConcreteTypeMunger existingMunger : ret) {
  197. ResolvedTypeMunger existing = existingMunger.getMunger();
  198. if (isNewStylePrivilegedAccessMunger(existing)) {
  199. String existingFieldName = existing.getSignature().getName();
  200. if (existingFieldName.equals(newFieldName)
  201. && existing.getSignature().getDeclaringType().equals(
  202. resolvedMungerToAdd.getSignature().getDeclaringType())) {
  203. alreadyExists = true;
  204. break;
  205. }
  206. }
  207. }
  208. if (!alreadyExists) {
  209. ret.add(mungerToAdd);
  210. }
  211. } else {
  212. ret.add(mungerToAdd);
  213. }
  214. }
  215. }
  216. typeMungers = ret;
  217. }
  218. return typeMungers;
  219. }
  220. /**
  221. * Retrieve a subset of all known mungers, those of a specific kind.
  222. *
  223. * @param kind the kind of munger requested
  224. * @return a list of those mungers (list is empty if none found)
  225. */
  226. public List<ConcreteTypeMunger> getTypeMungersOfKind(ResolvedTypeMunger.Kind kind) {
  227. List<ConcreteTypeMunger> collected = null;
  228. for (ConcreteTypeMunger typeMunger : typeMungers) {
  229. if (typeMunger.getMunger() != null && typeMunger.getMunger().getKind() == kind) {
  230. if (collected == null) {
  231. collected = new ArrayList<>();
  232. }
  233. collected.add(typeMunger);
  234. }
  235. }
  236. if (collected == null) {
  237. return Collections.emptyList();
  238. } else {
  239. return collected;
  240. }
  241. }
  242. /**
  243. * Determine if the type munger is: (1) for privileged access (2) for a normally non visible field (3) is from an aspect wanting
  244. * 'old style' (ie. long) accessor names
  245. */
  246. private boolean isNewStylePrivilegedAccessMunger(ResolvedTypeMunger typeMunger) {
  247. boolean b = (typeMunger != null && typeMunger.getKind() == ResolvedTypeMunger.PrivilegedAccess && typeMunger.getSignature()
  248. .getKind() == Member.FIELD);
  249. if (!b) {
  250. return b;
  251. }
  252. PrivilegedAccessMunger privAccessMunger = (PrivilegedAccessMunger) typeMunger;
  253. return privAccessMunger.shortSyntax;
  254. }
  255. public List<ConcreteTypeMunger> getLateTypeMungers() {
  256. if (lateTypeMungers == null) {
  257. List<ConcreteTypeMunger> ret = new ArrayList<>();
  258. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  259. ret.addAll(crosscuttingMembers.getLateTypeMungers());
  260. }
  261. lateTypeMungers = ret;
  262. }
  263. return lateTypeMungers;
  264. }
  265. public List<DeclareSoft> getDeclareSofts() {
  266. if (declareSofts == null) {
  267. Set<DeclareSoft> ret = new HashSet<>();
  268. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  269. ret.addAll(crosscuttingMembers.getDeclareSofts());
  270. }
  271. declareSofts = new ArrayList<>();
  272. declareSofts.addAll(ret);
  273. }
  274. return declareSofts;
  275. }
  276. public List<DeclareParents> getDeclareParents() {
  277. if (declareParents == null) {
  278. Set<DeclareParents> ret = new HashSet<>();
  279. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  280. ret.addAll(crosscuttingMembers.getDeclareParents());
  281. }
  282. declareParents = new ArrayList<>();
  283. declareParents.addAll(ret);
  284. }
  285. return declareParents;
  286. }
  287. /**
  288. * @return an amalgamation of the declare @type statements.
  289. */
  290. public List<DeclareAnnotation> getDeclareAnnotationOnTypes() {
  291. if (declareAnnotationOnTypes == null) {
  292. Set<DeclareAnnotation> ret = new LinkedHashSet<>();
  293. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  294. ret.addAll(crosscuttingMembers.getDeclareAnnotationOnTypes());
  295. }
  296. declareAnnotationOnTypes = new ArrayList<>();
  297. declareAnnotationOnTypes.addAll(ret);
  298. }
  299. return declareAnnotationOnTypes;
  300. }
  301. /**
  302. * @return an amalgamation of the declare @field statements.
  303. */
  304. public List<DeclareAnnotation> getDeclareAnnotationOnFields() {
  305. if (declareAnnotationOnFields == null) {
  306. Set<DeclareAnnotation> ret = new LinkedHashSet<>();
  307. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  308. ret.addAll(crosscuttingMembers.getDeclareAnnotationOnFields());
  309. }
  310. declareAnnotationOnFields = new ArrayList<>();
  311. declareAnnotationOnFields.addAll(ret);
  312. }
  313. return declareAnnotationOnFields;
  314. }
  315. /**
  316. * @return an amalgamation of the declare @method/@constructor statements.
  317. */
  318. public List<DeclareAnnotation> getDeclareAnnotationOnMethods() {
  319. if (declareAnnotationOnMethods == null) {
  320. Set<DeclareAnnotation> ret = new LinkedHashSet<>();
  321. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  322. ret.addAll(crosscuttingMembers.getDeclareAnnotationOnMethods());
  323. }
  324. declareAnnotationOnMethods = new ArrayList<>();
  325. declareAnnotationOnMethods.addAll(ret);
  326. // world.sortDeclareAnnotations(declareAnnotationOnMethods);
  327. }
  328. return declareAnnotationOnMethods;
  329. }
  330. /**
  331. * Return an amalgamation of the declare type eow statements
  332. */
  333. public List<DeclareTypeErrorOrWarning> getDeclareTypeEows() {
  334. if (declareTypeEows == null) {
  335. Set<DeclareTypeErrorOrWarning> ret = new HashSet<>();
  336. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  337. ret.addAll(crosscuttingMembers.getDeclareTypeErrorOrWarning());
  338. }
  339. declareTypeEows = new ArrayList<>();
  340. declareTypeEows.addAll(ret);
  341. }
  342. return declareTypeEows;
  343. }
  344. public List<Declare> getDeclareDominates() {
  345. if (declareDominates == null) {
  346. List<Declare> ret = new ArrayList<>();
  347. for (CrosscuttingMembers crosscuttingMembers : members.values()) {
  348. ret.addAll(crosscuttingMembers.getDeclareDominates());
  349. }
  350. declareDominates = ret;
  351. }
  352. return declareDominates;
  353. }
  354. public ResolvedType findAspectDeclaringParents(DeclareParents p) {
  355. Set<ResolvedType> keys = this.members.keySet();
  356. for (ResolvedType element : keys) {
  357. for (DeclareParents dp : members.get(element).getDeclareParents()) {
  358. if (dp.equals(p)) {
  359. return element;
  360. }
  361. }
  362. }
  363. return null;
  364. }
  365. public void reset() {
  366. verificationList = null;
  367. changedSinceLastReset = false;
  368. }
  369. public boolean hasChangedSinceLastReset() {
  370. return changedSinceLastReset;
  371. }
  372. /**
  373. * Record something that needs verifying when we believe the type system is complete. Used for things that can't be verified as
  374. * we go along - for example some recursive type variable references (pr133307)
  375. */
  376. public void recordNecessaryCheck(IVerificationRequired verification) {
  377. if (verificationList == null) {
  378. verificationList = new ArrayList<>();
  379. }
  380. verificationList.add(verification);
  381. }
  382. /**
  383. * Called when type bindings are complete - calls all registered verification objects in turn.
  384. */
  385. public void verify() {
  386. if (verificationList == null) {
  387. return;
  388. }
  389. for (IVerificationRequired element : verificationList) {
  390. element.verify();
  391. }
  392. verificationList = null;
  393. }
  394. public int serializationVersion = 1;
  395. public void write(CompressingDataOutputStream stream) throws IOException {
  396. // stream.writeInt(serializationVersion);
  397. stream.writeInt(shadowMungers.size());
  398. for (ShadowMunger shadowMunger : shadowMungers) {
  399. shadowMunger.write(stream);
  400. }
  401. // // private List /* ShadowMunger */shadowMungers = null;
  402. // // private List typeMungers = null;
  403. // // private List lateTypeMungers = null;
  404. // // private List declareSofts = null;
  405. // // private List declareParents = null;
  406. // // private List declareAnnotationOnTypes = null;
  407. // // private List declareAnnotationOnFields = null;
  408. // // private List declareAnnotationOnMethods = null; // includes constructors
  409. // // private List declareDominates = null;
  410. // // private boolean changedSinceLastReset = false;
  411. //
  412. }
  413. }