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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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 Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver;
  13. import java.util.ArrayList;
  14. import java.util.HashMap;
  15. import java.util.HashSet;
  16. import java.util.Iterator;
  17. import java.util.List;
  18. import java.util.Map;
  19. import java.util.Set;
  20. import org.aspectj.weaver.patterns.CflowPointcut;
  21. import org.aspectj.weaver.patterns.DeclareParents;
  22. import org.aspectj.weaver.patterns.IVerificationRequired;
  23. /**
  24. * This holds on to all CrosscuttingMembers for a world. It handles
  25. * management of change.
  26. *
  27. * @author Jim Hugunin
  28. */
  29. public class CrosscuttingMembersSet {
  30. private World world;
  31. //FIXME AV - ? we may need a sequencedHashMap there to ensure source based precedence for @AJ advice
  32. private Map /* ResolvedType (the aspect) > CrosscuttingMembers */members = new HashMap();
  33. private List shadowMungers = null;
  34. private List typeMungers = null;
  35. private List lateTypeMungers = null;
  36. private List declareSofts = null;
  37. private List declareParents = null;
  38. private List declareAnnotationOnTypes = null;
  39. private List declareAnnotationOnFields = null;
  40. private List declareAnnotationOnMethods= null; // includes ctors
  41. private List declareDominates = null;
  42. private boolean changedSinceLastReset = false;
  43. private List /*IVerificationRequired*/ verificationList = null; // List of things to be verified once the type system is 'complete'
  44. public CrosscuttingMembersSet(World world) {
  45. this.world = world;
  46. }
  47. public boolean addOrReplaceAspect(ResolvedType aspectType) {
  48. return addOrReplaceAspect(aspectType,true);
  49. }
  50. /**
  51. * @return whether or not that was a change to the global signature
  52. * XXX for efficiency we will need a richer representation than this
  53. */
  54. public boolean addOrReplaceAspect(ResolvedType aspectType,boolean careAboutShadowMungers) {
  55. boolean change = false;
  56. CrosscuttingMembers xcut = (CrosscuttingMembers)members.get(aspectType);
  57. if (xcut == null) {
  58. members.put(aspectType, aspectType.collectCrosscuttingMembers());
  59. clearCaches();
  60. CflowPointcut.clearCaches(aspectType);
  61. change = true;
  62. } else {
  63. if (xcut.replaceWith(aspectType.collectCrosscuttingMembers(),careAboutShadowMungers)) {
  64. clearCaches();
  65. CflowPointcut.clearCaches(aspectType);
  66. change = true;
  67. } else {
  68. if (careAboutShadowMungers) {
  69. // bug 134541 - even though we haven't changed we may have updated the
  70. // sourcelocation for the shadowMunger which we need to pick up
  71. shadowMungers = null;
  72. }
  73. change = false;
  74. }
  75. }
  76. if (aspectType.isAbstract()) {
  77. // we might have sub-aspects that need to re-collect their crosscutting members from us
  78. boolean ancestorChange = addOrReplaceDescendantsOf(aspectType,careAboutShadowMungers);
  79. change = change || ancestorChange;
  80. }
  81. changedSinceLastReset = changedSinceLastReset || change;
  82. return change;
  83. }
  84. private boolean addOrReplaceDescendantsOf(ResolvedType aspectType,boolean careAboutShadowMungers) {
  85. //System.err.println("Looking at descendants of "+aspectType.getName());
  86. Set knownAspects = members.keySet();
  87. Set toBeReplaced = new HashSet();
  88. for(Iterator it = knownAspects.iterator(); it.hasNext(); ) {
  89. ResolvedType candidateDescendant = (ResolvedType)it.next();
  90. if ((candidateDescendant != aspectType) && (aspectType.isAssignableFrom(candidateDescendant))) {
  91. toBeReplaced.add(candidateDescendant);
  92. }
  93. }
  94. boolean change = false;
  95. for (Iterator it = toBeReplaced.iterator(); it.hasNext(); ) {
  96. ResolvedType next = (ResolvedType)it.next();
  97. boolean thisChange = addOrReplaceAspect(next,careAboutShadowMungers);
  98. change = change || thisChange;
  99. }
  100. return change;
  101. }
  102. public void addAdviceLikeDeclares(ResolvedType aspectType) {
  103. CrosscuttingMembers xcut = (CrosscuttingMembers)members.get(aspectType);
  104. xcut.addDeclares(aspectType.collectDeclares(true));
  105. }
  106. public boolean deleteAspect(UnresolvedType aspectType) {
  107. boolean isAspect = members.remove(aspectType) != null;
  108. clearCaches();
  109. return isAspect;
  110. }
  111. public boolean containsAspect(UnresolvedType aspectType) {
  112. return members.containsKey(aspectType);
  113. }
  114. //XXX only for testing
  115. public void addFixedCrosscuttingMembers(ResolvedType aspectType) {
  116. members.put(aspectType, aspectType.crosscuttingMembers);
  117. clearCaches();
  118. }
  119. private void clearCaches() {
  120. shadowMungers = null;
  121. typeMungers = null;
  122. lateTypeMungers = null;
  123. declareSofts = null;
  124. declareParents = null;
  125. declareAnnotationOnFields=null;
  126. declareAnnotationOnMethods=null;
  127. declareAnnotationOnTypes=null;
  128. declareDominates = null;
  129. }
  130. public List getShadowMungers() {
  131. if (shadowMungers == null) {
  132. ArrayList ret = new ArrayList();
  133. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  134. ret.addAll(((CrosscuttingMembers)i.next()).getShadowMungers());
  135. }
  136. shadowMungers = ret;
  137. }
  138. return shadowMungers;
  139. }
  140. public List getTypeMungers() {
  141. if (typeMungers == null) {
  142. ArrayList ret = new ArrayList();
  143. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  144. ret.addAll(((CrosscuttingMembers)i.next()).getTypeMungers());
  145. }
  146. typeMungers = ret;
  147. }
  148. return typeMungers;
  149. }
  150. public List getLateTypeMungers() {
  151. if (lateTypeMungers == null) {
  152. ArrayList ret = new ArrayList();
  153. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  154. ret.addAll(((CrosscuttingMembers)i.next()).getLateTypeMungers());
  155. }
  156. lateTypeMungers = ret;
  157. }
  158. return lateTypeMungers;
  159. }
  160. public List getDeclareSofts() {
  161. if (declareSofts == null) {
  162. Set ret = new HashSet();
  163. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  164. ret.addAll(((CrosscuttingMembers)i.next()).getDeclareSofts());
  165. }
  166. declareSofts = new ArrayList();
  167. declareSofts.addAll(ret);
  168. }
  169. return declareSofts;
  170. }
  171. public List getDeclareParents() {
  172. if (declareParents == null) {
  173. Set ret = new HashSet();
  174. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  175. ret.addAll(((CrosscuttingMembers)i.next()).getDeclareParents());
  176. }
  177. declareParents = new ArrayList();
  178. declareParents.addAll(ret);
  179. }
  180. return declareParents;
  181. }
  182. // DECAT Merge multiple together
  183. public List getDeclareAnnotationOnTypes() {
  184. if (declareAnnotationOnTypes == null) {
  185. Set ret = new HashSet();
  186. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  187. ret.addAll(((CrosscuttingMembers)i.next()).getDeclareAnnotationOnTypes());
  188. }
  189. declareAnnotationOnTypes = new ArrayList();
  190. declareAnnotationOnTypes.addAll(ret);
  191. }
  192. return declareAnnotationOnTypes;
  193. }
  194. public List getDeclareAnnotationOnFields() {
  195. if (declareAnnotationOnFields == null) {
  196. Set ret = new HashSet();
  197. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  198. ret.addAll(((CrosscuttingMembers)i.next()).getDeclareAnnotationOnFields());
  199. }
  200. declareAnnotationOnFields = new ArrayList();
  201. declareAnnotationOnFields.addAll(ret);
  202. }
  203. return declareAnnotationOnFields;
  204. }
  205. /**
  206. * Return an amalgamation of the declare @method/@constructor statements.
  207. */
  208. public List getDeclareAnnotationOnMethods() {
  209. if (declareAnnotationOnMethods == null) {
  210. Set ret = new HashSet();
  211. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  212. ret.addAll(((CrosscuttingMembers)i.next()).getDeclareAnnotationOnMethods());
  213. }
  214. declareAnnotationOnMethods = new ArrayList();
  215. declareAnnotationOnMethods.addAll(ret);
  216. }
  217. return declareAnnotationOnMethods;
  218. }
  219. public List getDeclareDominates() {
  220. if (declareDominates == null) {
  221. ArrayList ret = new ArrayList();
  222. for (Iterator i = members.values().iterator(); i.hasNext(); ) {
  223. ret.addAll(((CrosscuttingMembers)i.next()).getDeclareDominates());
  224. }
  225. declareDominates = ret;
  226. }
  227. return declareDominates;
  228. }
  229. public ResolvedType findAspectDeclaringParents(DeclareParents p) {
  230. Set keys = this.members.keySet();
  231. for (Iterator iter = keys.iterator(); iter.hasNext();) {
  232. ResolvedType element = (ResolvedType) iter.next();
  233. for (Iterator i = ((CrosscuttingMembers)members.get(element)).getDeclareParents().iterator(); i.hasNext(); ) {
  234. DeclareParents dp = (DeclareParents)i.next();
  235. if (dp.equals(p)) return element;
  236. }
  237. }
  238. return null;
  239. }
  240. public void reset() {
  241. verificationList=null;
  242. changedSinceLastReset = false;
  243. }
  244. public boolean hasChangedSinceLastReset() {
  245. return changedSinceLastReset;
  246. }
  247. /**
  248. * Record something that needs verifying when we believe the type system is complete.
  249. * Used for things that can't be verified as we go along - for example some
  250. * recursive type variable references (pr133307)
  251. */
  252. public void recordNecessaryCheck(IVerificationRequired verification) {
  253. if (verificationList==null) verificationList = new ArrayList();
  254. verificationList.add(verification);
  255. }
  256. /**
  257. * Called when type bindings are complete - calls all registered verification
  258. * objects in turn.
  259. */
  260. public void verify() {
  261. if (verificationList==null) return;
  262. for (Iterator iter = verificationList.iterator(); iter.hasNext();) {
  263. IVerificationRequired element = (IVerificationRequired) iter.next();
  264. element.verify();
  265. }
  266. verificationList = null;
  267. }
  268. }