123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- /* *******************************************************************
- * Copyright (c) 2002-2009 Contributors
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.weaver;
-
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
-
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.weaver.patterns.Declare;
- import org.aspectj.weaver.patterns.DeclareAnnotation;
- import org.aspectj.weaver.patterns.DeclareParents;
- import org.aspectj.weaver.patterns.DeclareSoft;
- import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
- import org.aspectj.weaver.patterns.IVerificationRequired;
-
- /**
- * This holds on to all CrosscuttingMembers for a world. It handles management of change.
- *
- * @author Jim Hugunin
- * @author Andy Clement
- */
- public class CrosscuttingMembersSet {
-
- private transient World world;
-
- // FIXME AV - ? we may need a sequencedHashMap there to ensure source based precedence for @AJ advice
- private final Map<ResolvedType, CrosscuttingMembers> members = new HashMap<ResolvedType, CrosscuttingMembers>();
-
- // List of things to be verified once the type system is 'complete'
- private transient List<IVerificationRequired> verificationList = null;
-
- private List<ShadowMunger> shadowMungers = null;
- private List<ConcreteTypeMunger> typeMungers = null;
- private List<ConcreteTypeMunger> lateTypeMungers = null;
- private List<DeclareSoft> declareSofts = null;
- private List<DeclareParents> declareParents = null;
- private List<DeclareAnnotation> declareAnnotationOnTypes = null;
- private List<DeclareAnnotation> declareAnnotationOnFields = null;
- private List<DeclareAnnotation> declareAnnotationOnMethods = null; // includes constructors
- private List<DeclareTypeErrorOrWarning> declareTypeEows = null;
- private List<Declare> declareDominates = null;
- private boolean changedSinceLastReset = false;
-
- public CrosscuttingMembersSet(World world) {
- this.world = world;
- }
-
- public boolean addOrReplaceAspect(ResolvedType aspectType) {
- return addOrReplaceAspect(aspectType, true);
- }
-
- /**
- * Check if any parent aspects of the supplied aspect have unresolved dependencies (and so
- * should cause this aspect to be turned off).
- * @param aspectType the aspect whose parents should be checked
- * @return true if this aspect should be excluded because of a parents' missing dependencies
- */
- private boolean excludeDueToParentAspectHavingUnresolvedDependency(ResolvedType aspectType) {
- ResolvedType parent = aspectType.getSuperclass();
- boolean excludeDueToParent = false;
- while (parent != null) {
- if (parent.isAspect() && parent.isAbstract() && world.hasUnsatisfiedDependency(parent)) {
- if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
- world.getMessageHandler().handleMessage(
- MessageUtil.info("deactivating aspect '" + aspectType.getName() + "' as the parent aspect '"+parent.getName()+
- "' has unsatisfied dependencies"));
- }
- excludeDueToParent = true;
- }
- parent = parent.getSuperclass();
- }
- return excludeDueToParent;
- }
-
- /**
- * @return whether or not that was a change to the global signature XXX for efficiency we will need a richer representation than
- * this
- */
- public boolean addOrReplaceAspect(ResolvedType aspectType, boolean inWeavingPhase) {
- if (!world.isAspectIncluded(aspectType)) {
- return false;
- }
- if (world.hasUnsatisfiedDependency(aspectType)) {
- return false;
- }
- // Abstract super aspects might have unsatisfied dependencies
- if (excludeDueToParentAspectHavingUnresolvedDependency(aspectType)) {
- return false;
- }
-
- boolean change = false;
- CrosscuttingMembers xcut = members.get(aspectType);
- if (xcut == null) {
- members.put(aspectType, aspectType.collectCrosscuttingMembers(inWeavingPhase));
- clearCaches();
- change = true;
- } else {
- if (xcut.replaceWith(aspectType.collectCrosscuttingMembers(inWeavingPhase), inWeavingPhase)) {
- clearCaches();
- change = true;
- } else {
- if (inWeavingPhase) {
- // bug 134541 - even though we haven't changed we may have updated the
- // sourcelocation for the shadowMunger which we need to pick up
- shadowMungers = null;
- }
- change = false;
- }
- }
- if (aspectType.isAbstract()) {
- // we might have sub-aspects that need to re-collect their crosscutting members from us
- boolean ancestorChange = addOrReplaceDescendantsOf(aspectType, inWeavingPhase);
- change = change || ancestorChange;
- }
- changedSinceLastReset = changedSinceLastReset || change;
-
- return change;
- }
-
- private boolean addOrReplaceDescendantsOf(ResolvedType aspectType, boolean inWeavePhase) {
- // System.err.println("Looking at descendants of "+aspectType.getName());
- Set<ResolvedType> knownAspects = members.keySet();
- Set<ResolvedType> toBeReplaced = new HashSet<ResolvedType>();
- for (Iterator<ResolvedType> it = knownAspects.iterator(); it.hasNext();) {
- ResolvedType candidateDescendant = it.next();
- // allowMissing = true - if something is missing, it really probably is not a descendant
- if ((candidateDescendant != aspectType) && (aspectType.isAssignableFrom(candidateDescendant, true))) {
- toBeReplaced.add(candidateDescendant);
- }
- }
- boolean change = false;
- for (Iterator<ResolvedType> it = toBeReplaced.iterator(); it.hasNext();) {
- ResolvedType next = it.next();
- boolean thisChange = addOrReplaceAspect(next, inWeavePhase);
- change = change || thisChange;
- }
- return change;
- }
-
- public void addAdviceLikeDeclares(ResolvedType aspectType) {
- if (!members.containsKey(aspectType)) {
- return;
- }
- CrosscuttingMembers xcut = members.get(aspectType);
- xcut.addDeclares(aspectType.collectDeclares(true));
- }
-
- public boolean deleteAspect(UnresolvedType aspectType) {
- boolean isAspect = members.remove(aspectType) != null;
- clearCaches();
- return isAspect;
- }
-
- public boolean containsAspect(UnresolvedType aspectType) {
- return members.containsKey(aspectType);
- }
-
- // XXX only for testing
- public void addFixedCrosscuttingMembers(ResolvedType aspectType) {
- members.put(aspectType, aspectType.crosscuttingMembers);
- clearCaches();
- }
-
- private void clearCaches() {
- shadowMungers = null;
- typeMungers = null;
- lateTypeMungers = null;
- declareSofts = null;
- declareParents = null;
- declareAnnotationOnFields = null;
- declareAnnotationOnMethods = null;
- declareAnnotationOnTypes = null;
- declareDominates = null;
- }
-
- public List<ShadowMunger> getShadowMungers() {
- if (shadowMungers == null) {
- List<ShadowMunger> ret = new ArrayList<ShadowMunger>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getShadowMungers());
- }
- shadowMungers = ret;
- }
- return shadowMungers;
- }
-
- public List<ConcreteTypeMunger> getTypeMungers() {
- if (typeMungers == null) {
- List<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
- for (CrosscuttingMembers xmembers : members.values()) {
- // With 1.6.9 there is a change that enables use of more optimal accessors (accessors for private fields).
- // Here is where we determine if two aspects are asking for access to the same field. If they are
- // and
- // In the new style multiple aspects can share the same privileged accessors, so here we check if
- // two aspects are asking for access to the same field. If they are then we don't add a duplicate
- // accessor.
- for (ConcreteTypeMunger mungerToAdd : xmembers.getTypeMungers()) {
- ResolvedTypeMunger resolvedMungerToAdd = mungerToAdd.getMunger();
- if (isNewStylePrivilegedAccessMunger(resolvedMungerToAdd)) {
- String newFieldName = resolvedMungerToAdd.getSignature().getName();
- boolean alreadyExists = false;
- for (ConcreteTypeMunger existingMunger : ret) {
- ResolvedTypeMunger existing = existingMunger.getMunger();
- if (isNewStylePrivilegedAccessMunger(existing)) {
- String existingFieldName = existing.getSignature().getName();
- if (existingFieldName.equals(newFieldName)
- && existing.getSignature().getDeclaringType().equals(
- resolvedMungerToAdd.getSignature().getDeclaringType())) {
- alreadyExists = true;
- break;
- }
- }
- }
- if (!alreadyExists) {
- ret.add(mungerToAdd);
- }
- } else {
- ret.add(mungerToAdd);
- }
- }
- }
- typeMungers = ret;
- }
- return typeMungers;
- }
-
- /**
- * Retrieve a subset of all known mungers, those of a specific kind.
- *
- * @param kind the kind of munger requested
- * @return a list of those mungers (list is empty if none found)
- */
- public List<ConcreteTypeMunger> getTypeMungersOfKind(ResolvedTypeMunger.Kind kind) {
- List<ConcreteTypeMunger> collected = null;
- for (ConcreteTypeMunger typeMunger : typeMungers) {
- if (typeMunger.getMunger() != null && typeMunger.getMunger().getKind() == kind) {
- if (collected == null) {
- collected = new ArrayList<ConcreteTypeMunger>();
- }
- collected.add(typeMunger);
- }
- }
- if (collected == null) {
- return Collections.emptyList();
- } else {
- return collected;
- }
- }
-
- /**
- * Determine if the type munger is: (1) for privileged access (2) for a normally non visible field (3) is from an aspect wanting
- * 'old style' (ie. long) accessor names
- */
- private boolean isNewStylePrivilegedAccessMunger(ResolvedTypeMunger typeMunger) {
- boolean b = (typeMunger != null && typeMunger.getKind() == ResolvedTypeMunger.PrivilegedAccess && typeMunger.getSignature()
- .getKind() == Member.FIELD);
- if (!b) {
- return b;
- }
- PrivilegedAccessMunger privAccessMunger = (PrivilegedAccessMunger) typeMunger;
- return privAccessMunger.shortSyntax;
- }
-
- public List<ConcreteTypeMunger> getLateTypeMungers() {
- if (lateTypeMungers == null) {
- List<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getLateTypeMungers());
- }
- lateTypeMungers = ret;
- }
- return lateTypeMungers;
- }
-
- public List<DeclareSoft> getDeclareSofts() {
- if (declareSofts == null) {
- Set<DeclareSoft> ret = new HashSet<DeclareSoft>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getDeclareSofts());
- }
- declareSofts = new ArrayList<DeclareSoft>();
- declareSofts.addAll(ret);
- }
- return declareSofts;
- }
-
- public List<DeclareParents> getDeclareParents() {
- if (declareParents == null) {
- Set<DeclareParents> ret = new HashSet<DeclareParents>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getDeclareParents());
- }
- declareParents = new ArrayList<DeclareParents>();
- declareParents.addAll(ret);
- }
- return declareParents;
- }
-
- /**
- * @return an amalgamation of the declare @type statements.
- */
- public List<DeclareAnnotation> getDeclareAnnotationOnTypes() {
- if (declareAnnotationOnTypes == null) {
- Set<DeclareAnnotation> ret = new LinkedHashSet<DeclareAnnotation>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getDeclareAnnotationOnTypes());
- }
- declareAnnotationOnTypes = new ArrayList<DeclareAnnotation>();
- declareAnnotationOnTypes.addAll(ret);
- }
- return declareAnnotationOnTypes;
- }
-
- /**
- * @return an amalgamation of the declare @field statements.
- */
- public List<DeclareAnnotation> getDeclareAnnotationOnFields() {
- if (declareAnnotationOnFields == null) {
- Set<DeclareAnnotation> ret = new LinkedHashSet<DeclareAnnotation>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getDeclareAnnotationOnFields());
- }
- declareAnnotationOnFields = new ArrayList<DeclareAnnotation>();
- declareAnnotationOnFields.addAll(ret);
- }
- return declareAnnotationOnFields;
- }
-
- /**
- * @return an amalgamation of the declare @method/@constructor statements.
- */
- public List<DeclareAnnotation> getDeclareAnnotationOnMethods() {
- if (declareAnnotationOnMethods == null) {
- Set<DeclareAnnotation> ret = new LinkedHashSet<DeclareAnnotation>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getDeclareAnnotationOnMethods());
- }
- declareAnnotationOnMethods = new ArrayList<DeclareAnnotation>();
- declareAnnotationOnMethods.addAll(ret);
- // world.sortDeclareAnnotations(declareAnnotationOnMethods);
- }
- return declareAnnotationOnMethods;
- }
-
- /**
- * Return an amalgamation of the declare type eow statements
- */
- public List<DeclareTypeErrorOrWarning> getDeclareTypeEows() {
- if (declareTypeEows == null) {
- Set<DeclareTypeErrorOrWarning> ret = new HashSet<DeclareTypeErrorOrWarning>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getDeclareTypeErrorOrWarning());
- }
- declareTypeEows = new ArrayList<DeclareTypeErrorOrWarning>();
- declareTypeEows.addAll(ret);
- }
- return declareTypeEows;
- }
-
- public List<Declare> getDeclareDominates() {
- if (declareDominates == null) {
- List<Declare> ret = new ArrayList<Declare>();
- for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
- ret.addAll(i.next().getDeclareDominates());
- }
- declareDominates = ret;
- }
- return declareDominates;
- }
-
- public ResolvedType findAspectDeclaringParents(DeclareParents p) {
- Set<ResolvedType> keys = this.members.keySet();
- for (Iterator<ResolvedType> iter = keys.iterator(); iter.hasNext();) {
- ResolvedType element = iter.next();
- for (Iterator i = members.get(element).getDeclareParents().iterator(); i.hasNext();) {
- DeclareParents dp = (DeclareParents) i.next();
- if (dp.equals(p)) {
- return element;
- }
- }
- }
- return null;
- }
-
- public void reset() {
- verificationList = null;
- changedSinceLastReset = false;
- }
-
- public boolean hasChangedSinceLastReset() {
- return changedSinceLastReset;
- }
-
- /**
- * Record something that needs verifying when we believe the type system is complete. Used for things that can't be verified as
- * we go along - for example some recursive type variable references (pr133307)
- */
- public void recordNecessaryCheck(IVerificationRequired verification) {
- if (verificationList == null) {
- verificationList = new ArrayList<IVerificationRequired>();
- }
- verificationList.add(verification);
- }
-
- /**
- * Called when type bindings are complete - calls all registered verification objects in turn.
- */
- public void verify() {
- if (verificationList == null) {
- return;
- }
- for (Iterator<IVerificationRequired> iter = verificationList.iterator(); iter.hasNext();) {
- IVerificationRequired element = iter.next();
- element.verify();
- }
- verificationList = null;
- }
-
- public int serializationVersion = 1;
-
- public void write(CompressingDataOutputStream stream) throws IOException {
- // stream.writeInt(serializationVersion);
- stream.writeInt(shadowMungers.size());
- for (Iterator iterator = shadowMungers.iterator(); iterator.hasNext();) {
- ShadowMunger shadowMunger = (ShadowMunger) iterator.next();
- shadowMunger.write(stream);
- }
- // // private List /* ShadowMunger */shadowMungers = null;
- // // private List typeMungers = null;
- // // private List lateTypeMungers = null;
- // // private List declareSofts = null;
- // // private List declareParents = null;
- // // private List declareAnnotationOnTypes = null;
- // // private List declareAnnotationOnFields = null;
- // // private List declareAnnotationOnMethods = null; // includes constructors
- // // private List declareDominates = null;
- // // private boolean changedSinceLastReset = false;
- //
- }
- }
|