123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * 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.util.ArrayList;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.Hashtable;
- import java.util.Iterator;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
-
- import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
- import org.aspectj.weaver.patterns.Declare;
- import org.aspectj.weaver.patterns.DeclareAnnotation;
- import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
- import org.aspectj.weaver.patterns.DeclareParents;
- import org.aspectj.weaver.patterns.DeclarePrecedence;
- import org.aspectj.weaver.patterns.DeclareSoft;
- import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
- import org.aspectj.weaver.patterns.PerClause;
- import org.aspectj.weaver.patterns.Pointcut;
- import org.aspectj.weaver.patterns.PointcutRewriter;
-
- /**
- * This holds on to all members that have an invasive effect outside of there own compilation unit. These members need to be all
- * gathered up and in a world before any weaving can take place.
- *
- * They are also important in the compilation process and need to be gathered up before the inter-type declaration weaving stage
- * (unsurprisingly).
- *
- * All members are concrete.
- *
- * @author Jim Hugunin
- */
- public class CrosscuttingMembers {
- private final ResolvedType inAspect;
- private final World world;
-
- private PerClause perClause;
-
- private List<ShadowMunger> shadowMungers = new ArrayList<ShadowMunger>(4);
- private List<ConcreteTypeMunger> typeMungers = new ArrayList<ConcreteTypeMunger>(4);
- private List<ConcreteTypeMunger> lateTypeMungers = new ArrayList<ConcreteTypeMunger>(0);
-
- private Set<DeclareParents> declareParents = new HashSet<DeclareParents>();
- private Set<DeclareSoft> declareSofts = new HashSet<DeclareSoft>();
- private List<Declare> declareDominates = new ArrayList<Declare>(4);
-
- // These are like declare parents type mungers
- private Set<DeclareAnnotation> declareAnnotationsOnType = new LinkedHashSet<DeclareAnnotation>();
- private Set<DeclareAnnotation> declareAnnotationsOnField = new LinkedHashSet<DeclareAnnotation>();
- private Set<DeclareAnnotation> declareAnnotationsOnMethods = new LinkedHashSet<DeclareAnnotation>();
- // declareAnnotationsOnMethods includes constructors too
-
- private Set<DeclareTypeErrorOrWarning> declareTypeEow = new HashSet<DeclareTypeErrorOrWarning>();
-
- private boolean shouldConcretizeIfNeeded = true;
-
- public CrosscuttingMembers(ResolvedType inAspect, boolean shouldConcretizeIfNeeded) {
- this.inAspect = inAspect;
- world = inAspect.getWorld();
- this.shouldConcretizeIfNeeded = shouldConcretizeIfNeeded;
- }
-
- private final Hashtable<String, Object> cflowFields = new Hashtable<String, Object>();
- private final Hashtable<String, Object> cflowBelowFields = new Hashtable<String, Object>();
-
- // public void addConcreteShadowMungers(Collection c) {
- // shadowMungers.addAll(c);
- // }
-
- public void addConcreteShadowMunger(ShadowMunger m) {
- // assert m is concrete
- shadowMungers.add(m);
- }
-
- public void addShadowMungers(Collection<ShadowMunger> c) {
- for (ShadowMunger munger : c) {
- addShadowMunger(munger);
- }
- }
-
- private void addShadowMunger(ShadowMunger m) {
- if (inAspect.isAbstract()) {
- return; // mungers for abstract aspects are not added
- }
- addConcreteShadowMunger(m.concretize(inAspect, world, perClause));
- }
-
- public void addTypeMungers(Collection<ConcreteTypeMunger> c) {
- typeMungers.addAll(c);
- }
-
- public void addTypeMunger(ConcreteTypeMunger m) {
- if (m == null) {
- throw new Error("FIXME AV - should not happen or what ?");// return;
- }
- typeMungers.add(m);
- }
-
- public void addLateTypeMungers(Collection<ConcreteTypeMunger> c) {
- lateTypeMungers.addAll(c);
- }
-
- public void addLateTypeMunger(ConcreteTypeMunger m) {
- lateTypeMungers.add(m);
- }
-
- public void addDeclares(Collection<Declare> declares) {
- for (Declare declare : declares) {
- addDeclare(declare);
- }
- }
-
- public void addDeclare(Declare declare) {
- // this is not extensible, oh well
- if (declare instanceof DeclareErrorOrWarning) {
- ShadowMunger m = new Checker((DeclareErrorOrWarning) declare);
- m.setDeclaringType(declare.getDeclaringType());
- addShadowMunger(m);
- } else if (declare instanceof DeclarePrecedence) {
- declareDominates.add(declare);
- } else if (declare instanceof DeclareParents) {
- DeclareParents dp = (DeclareParents) declare;
- exposeTypes(dp.getParents().getExactTypes());
- declareParents.add(dp);
- } else if (declare instanceof DeclareSoft) {
- DeclareSoft d = (DeclareSoft) declare;
- // Ordered so that during concretization we can check the related
- // munger
- ShadowMunger m = Advice.makeSoftener(world, d.getPointcut(), d.getException(), inAspect, d);
- m.setDeclaringType(d.getDeclaringType());
- Pointcut concretePointcut = d.getPointcut().concretize(inAspect, d.getDeclaringType(), 0, m);
- m.pointcut = concretePointcut;
- declareSofts.add(new DeclareSoft(d.getException(), concretePointcut));
- addConcreteShadowMunger(m);
- } else if (declare instanceof DeclareAnnotation) {
- // FIXME asc perf Possible Improvement. Investigate why this is
- // called twice in a weave ?
- DeclareAnnotation da = (DeclareAnnotation) declare;
- if (da.getAspect() == null) {
- da.setAspect(inAspect);
- }
- if (da.isDeclareAtType()) {
- declareAnnotationsOnType.add(da);
- } else if (da.isDeclareAtField()) {
- declareAnnotationsOnField.add(da);
- } else if (da.isDeclareAtMethod() || da.isDeclareAtConstuctor()) {
- declareAnnotationsOnMethods.add(da);
- }
- } else if (declare instanceof DeclareTypeErrorOrWarning) {
- declareTypeEow.add((DeclareTypeErrorOrWarning) declare);
- } else {
- throw new RuntimeException("unimplemented");
- }
- }
-
- public void exposeTypes(List<UnresolvedType> typesToExpose) {
- for (UnresolvedType typeToExpose : typesToExpose) {
- exposeType(typeToExpose);
- }
- }
-
- public void exposeType(UnresolvedType typeToExpose) {
- if (ResolvedType.isMissing(typeToExpose)) {
- return;
- }
- if (typeToExpose.isParameterizedType() || typeToExpose.isRawType()) {
- if (typeToExpose instanceof ResolvedType) {
- typeToExpose = ((ResolvedType) typeToExpose).getGenericType();
- } else {
- typeToExpose = UnresolvedType.forSignature(typeToExpose.getErasureSignature());
- }
- }
- // Check we haven't already got a munger for this:
- String signatureToLookFor = typeToExpose.getSignature();
- for (Iterator<ConcreteTypeMunger> iterator = typeMungers.iterator(); iterator.hasNext();) {
- ConcreteTypeMunger cTM = iterator.next();
- ResolvedTypeMunger rTM = cTM.getMunger();
- if (rTM != null && rTM instanceof ExposeTypeMunger) {
- String exposedType = ((ExposeTypeMunger) rTM).getExposedTypeSignature();
- if (exposedType.equals(signatureToLookFor)) {
- return; // dont need to bother
- }
- }
- }
- addTypeMunger(world.getWeavingSupport().concreteTypeMunger(new ExposeTypeMunger(typeToExpose), inAspect));
- // ResolvedMember member = new ResolvedMemberImpl(
- // Member.STATIC_INITIALIZATION, typeToExpose, 0, UnresolvedType.VOID,
- // "<clinit>", UnresolvedType.NONE);
- // addTypeMunger(world.concreteTypeMunger(
- // new PrivilegedAccessMunger(member), inAspect));
- }
-
- public void addPrivilegedAccesses(Collection<ResolvedMember> accessedMembers) {
- int version = inAspect.getCompilerVersion();
- for (ResolvedMember member : accessedMembers) {
- // Looking it up ensures we get the annotations - the accessedMembers are just retrieved from the attribute and
- // don't have that information
- ResolvedMember resolvedMember = world.resolve(member);
-
- // pr333469
- // If the member is for an ITD (e.g. serialVersionUID) then during resolution we may resolve it on
- // a supertype because it doesn't yet exist on the target.
- // For example: MyList extends ArrayList<String> and the ITD is on MyList - after resolution it may be:
- // ArrayList<String>.serialVersionUID, we need to avoid that happening
-
- if (resolvedMember == null) {
- // can happen for ITDs - are there many privileged access ITDs??
- resolvedMember = member;
- if (resolvedMember.hasBackingGenericMember()) {
- resolvedMember = resolvedMember.getBackingGenericMember();
- }
- } else {
- UnresolvedType unresolvedDeclaringType = member.getDeclaringType().getRawType();
- UnresolvedType resolvedDeclaringType = resolvedMember.getDeclaringType().getRawType();
- if (!unresolvedDeclaringType.equals(resolvedDeclaringType)) {
- resolvedMember = member;
- }
- }
- PrivilegedAccessMunger privilegedAccessMunger = new PrivilegedAccessMunger(resolvedMember,
- version >= WeaverVersionInfo.WEAVER_VERSION_AJ169);
- ConcreteTypeMunger concreteTypeMunger = world.getWeavingSupport().concreteTypeMunger(privilegedAccessMunger, inAspect);
- addTypeMunger(concreteTypeMunger);
- }
- }
-
- public Collection<ShadowMunger> getCflowEntries() {
- List<ShadowMunger> ret = new ArrayList<ShadowMunger>();
- for (ShadowMunger m : shadowMungers) {
- if (m instanceof Advice) {
- Advice a = (Advice) m;
- if (a.getKind().isCflow()) {
- ret.add(a);
- }
- }
- }
- return ret;
- }
-
- /**
- * Updates the records if something has changed. This is called at most twice, firstly whilst collecting ITDs and declares. At
- * this point the CrosscuttingMembers we're comparing ourselves with doesn't know about shadowmungers. Therefore a straight
- * comparison with the existing list of shadowmungers would return that something has changed even though it might not have, so
- * in this first round we ignore the shadowMungers. The second time this is called is whilst we're preparing to weave. At this
- * point we know everything in the system and so we're able to compare the shadowMunger list. (see bug 129163)
- *
- * @param other
- * @param careAboutShadowMungers
- * @return true if something has changed since the last time this method was called, false otherwise
- */
- public boolean replaceWith(CrosscuttingMembers other, boolean careAboutShadowMungers) {
- boolean changed = false;
-
- if (careAboutShadowMungers) {
- if (perClause == null || !perClause.equals(other.perClause)) {
- changed = true;
- perClause = other.perClause;
- }
- }
-
- // XXX all of the below should be set equality rather than list equality
- // System.err.println("old: " + shadowMungers + " new: " +
- // other.shadowMungers);
-
- if (careAboutShadowMungers) {
- // bug 129163: use set equality rather than list equality
- Set<ShadowMunger> theseShadowMungers = new HashSet<ShadowMunger>();
- Set<ShadowMunger> theseInlinedAroundMungers = new HashSet<ShadowMunger>();
- for (ShadowMunger munger : shadowMungers) {
- if (munger instanceof Advice) {
- Advice adviceMunger = (Advice) munger;
- // bug 154054: if we're around advice that has been inlined
- // then we need to do more checking than existing equals
- // methods allow
- if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
- theseInlinedAroundMungers.add(adviceMunger);
- } else {
- theseShadowMungers.add(adviceMunger);
- }
- } else {
- theseShadowMungers.add(munger);
- }
- }
- Set<ShadowMunger> tempSet = new HashSet<ShadowMunger>();
- tempSet.addAll(other.shadowMungers);
- Set<ShadowMunger> otherShadowMungers = new HashSet<ShadowMunger>();
- Set<ShadowMunger> otherInlinedAroundMungers = new HashSet<ShadowMunger>();
- for (ShadowMunger munger : tempSet) {
- if (munger instanceof Advice) {
- Advice adviceMunger = (Advice) munger;
- // bug 154054: if we're around advice that has been inlined
- // then we need to do more checking than existing equals
- // methods allow
- if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
- otherInlinedAroundMungers.add(rewritePointcutInMunger(adviceMunger));
- } else {
- otherShadowMungers.add(rewritePointcutInMunger(adviceMunger));
- }
- } else {
- otherShadowMungers.add(rewritePointcutInMunger(munger));
- }
- }
- if (!theseShadowMungers.equals(otherShadowMungers)) {
- changed = true;
- }
- if (!equivalent(theseInlinedAroundMungers, otherInlinedAroundMungers)) {
- changed = true;
- }
-
- // bug 158573 - if there are no changes then preserve whether
- // or not a particular shadowMunger has matched something.
- if (!changed) {
- for (ShadowMunger munger : shadowMungers) {
- int i = other.shadowMungers.indexOf(munger);
- ShadowMunger otherMunger = other.shadowMungers.get(i);
- if (munger instanceof Advice) {
- ((Advice) otherMunger).setHasMatchedSomething(((Advice) munger).hasMatchedSomething());
- }
- }
- }
- // replace the existing list of shadowmungers with the
- // new ones in case anything like the sourcelocation has
- // changed, however, don't want this flagged as a change
- // which will force a full build - bug 134541
- shadowMungers = other.shadowMungers;
- }
-
- // bug 129163: use set equality rather than list equality and
- // if we dont care about shadow mungers then ignore those
- // typeMungers which are created to help with the implementation
- // of shadowMungers
- Set<Object> theseTypeMungers = new HashSet<Object>();
- Set<Object> otherTypeMungers = new HashSet<Object>();
- if (!careAboutShadowMungers) {
- for (Iterator<ConcreteTypeMunger> iter = typeMungers.iterator(); iter.hasNext();) {
- Object o = iter.next();
- if (o instanceof ConcreteTypeMunger) {
- ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) o;
- if (!typeMunger.existsToSupportShadowMunging()) {
- theseTypeMungers.add(typeMunger);
- }
- } else {
- theseTypeMungers.add(o);
- }
- }
-
- for (Iterator<ConcreteTypeMunger> iter = other.typeMungers.iterator(); iter.hasNext();) {
- Object o = iter.next();
- if (o instanceof ConcreteTypeMunger) {
- ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) o;
- if (!typeMunger.existsToSupportShadowMunging()) {
- otherTypeMungers.add(typeMunger);
- }
- } else {
- otherTypeMungers.add(o);
- }
- }
- } else {
- theseTypeMungers.addAll(typeMungers);
- otherTypeMungers.addAll(other.typeMungers);
- }
-
- // initial go at equivalence logic rather than set compare (see
- // pr133532)
- if (theseTypeMungers.size() != otherTypeMungers.size()) {
- changed = true;
- typeMungers = other.typeMungers;
- } else {
- boolean shouldOverwriteThis = false;
- boolean foundInequality = false;
- for (Iterator<Object> iter = theseTypeMungers.iterator(); iter.hasNext() && !foundInequality;) {
- Object thisOne = iter.next();
- boolean foundInOtherSet = false;
- for (Object otherOne : otherTypeMungers) {
- if (thisOne instanceof ConcreteTypeMunger) {
- if (((ConcreteTypeMunger) thisOne).shouldOverwrite()) {
- shouldOverwriteThis = true;
- }
- }
- if (thisOne instanceof ConcreteTypeMunger && otherOne instanceof ConcreteTypeMunger) {
- if (((ConcreteTypeMunger) thisOne).equivalentTo(otherOne)) {
- foundInOtherSet = true;
- } else if (thisOne.equals(otherOne)) {
- foundInOtherSet = true;
- }
- } else {
- if (thisOne.equals(otherOne)) {
- foundInOtherSet = true;
- }
- }
- }
- if (!foundInOtherSet) {
- foundInequality = true;
- }
- }
- if (foundInequality) {
- // System.out.println("type munger change");
- changed = true;
- }
- if (shouldOverwriteThis) {
- typeMungers = other.typeMungers;
- }
- }
- // if (!theseTypeMungers.equals(otherTypeMungers)) {
- // changed = true;
- // typeMungers = other.typeMungers;
- // }
-
- if (!lateTypeMungers.equals(other.lateTypeMungers)) {
- changed = true;
- lateTypeMungers = other.lateTypeMungers;
- }
-
- if (!declareDominates.equals(other.declareDominates)) {
- changed = true;
- declareDominates = other.declareDominates;
- }
-
- if (!declareParents.equals(other.declareParents)) {
- // Are the differences just because of a mixin? These are not created until weave time so should be gotten rid of for
- // the up front comparison
- if (!careAboutShadowMungers) {
- // this means we are in front end compilation and if the differences are purely mixin parents, we can continue OK
- Set<DeclareParents> trimmedThis = new HashSet<DeclareParents>();
- for (Iterator<DeclareParents> iterator = declareParents.iterator(); iterator.hasNext();) {
- DeclareParents decp = iterator.next();
- if (!decp.isMixin()) {
- trimmedThis.add(decp);
- }
- }
- Set<DeclareParents> trimmedOther = new HashSet<DeclareParents>();
- for (Iterator<DeclareParents> iterator = other.declareParents.iterator(); iterator.hasNext();) {
- DeclareParents decp = iterator.next();
- if (!decp.isMixin()) {
- trimmedOther.add(decp);
- }
- }
- if (!trimmedThis.equals(trimmedOther)) {
- changed = true;
- declareParents = other.declareParents;
- }
- } else {
- changed = true;
- declareParents = other.declareParents;
- }
- }
-
- if (!declareSofts.equals(other.declareSofts)) {
- changed = true;
- declareSofts = other.declareSofts;
- }
-
- // DECAT for when attempting to replace an aspect
- if (!declareAnnotationsOnType.equals(other.declareAnnotationsOnType)) {
- changed = true;
- declareAnnotationsOnType = other.declareAnnotationsOnType;
- }
-
- if (!declareAnnotationsOnField.equals(other.declareAnnotationsOnField)) {
- changed = true;
- declareAnnotationsOnField = other.declareAnnotationsOnField;
- }
-
- if (!declareAnnotationsOnMethods.equals(other.declareAnnotationsOnMethods)) {
- changed = true;
- declareAnnotationsOnMethods = other.declareAnnotationsOnMethods;
- }
- if (!declareTypeEow.equals(other.declareTypeEow)) {
- changed = true;
- declareTypeEow = other.declareTypeEow;
- }
-
- return changed;
- }
-
- private boolean equivalent(Set<ShadowMunger> theseInlinedAroundMungers, Set<ShadowMunger> otherInlinedAroundMungers) {
- if (theseInlinedAroundMungers.size() != otherInlinedAroundMungers.size()) {
- return false;
- }
- for (Iterator<ShadowMunger> iter = theseInlinedAroundMungers.iterator(); iter.hasNext();) {
- Advice thisAdvice = (Advice) iter.next();
- boolean foundIt = false;
- for (Iterator<ShadowMunger> iterator = otherInlinedAroundMungers.iterator(); iterator.hasNext();) {
- Advice otherAdvice = (Advice) iterator.next();
- if (thisAdvice.equals(otherAdvice)) {
- if (thisAdvice.getSignature() instanceof ResolvedMemberImpl) {
- if (((ResolvedMemberImpl) thisAdvice.getSignature()).isEquivalentTo(otherAdvice.getSignature())) {
- foundIt = true;
- continue;
- }
- }
- return false;
- }
- }
- if (!foundIt) {
- return false;
- }
- }
- return true;
- }
-
- private ShadowMunger rewritePointcutInMunger(ShadowMunger munger) {
- PointcutRewriter pr = new PointcutRewriter();
- Pointcut p = munger.getPointcut();
- Pointcut newP = pr.rewrite(p);
- if (p.m_ignoreUnboundBindingForNames.length != 0) {
- // *sigh* dirty fix for dirty hacky implementation pr149305
- newP.m_ignoreUnboundBindingForNames = p.m_ignoreUnboundBindingForNames;
- }
- munger.setPointcut(newP);
- return munger;
- }
-
- public void setPerClause(PerClause perClause) {
- if (shouldConcretizeIfNeeded) {
- this.perClause = perClause.concretize(inAspect);
- } else {
- this.perClause = perClause;
- }
- }
-
- public List<Declare> getDeclareDominates() {
- return declareDominates;
- }
-
- public Collection<DeclareParents> getDeclareParents() {
- return declareParents;
- }
-
- public Collection<DeclareSoft> getDeclareSofts() {
- return declareSofts;
- }
-
- public List<ShadowMunger> getShadowMungers() {
- return shadowMungers;
- }
-
- public List<ConcreteTypeMunger> getTypeMungers() {
- return typeMungers;
- }
-
- public List<ConcreteTypeMunger> getLateTypeMungers() {
- return lateTypeMungers;
- }
-
- public Collection<DeclareAnnotation> getDeclareAnnotationOnTypes() {
- return declareAnnotationsOnType;
- }
-
- public Collection<DeclareAnnotation> getDeclareAnnotationOnFields() {
- return declareAnnotationsOnField;
- }
-
- /**
- * includes declare @method and @constructor
- */
- public Collection<DeclareAnnotation> getDeclareAnnotationOnMethods() {
- return declareAnnotationsOnMethods;
- }
-
- public Collection<DeclareTypeErrorOrWarning> getDeclareTypeErrorOrWarning() {
- return declareTypeEow;
- }
-
- public Map<String, Object> getCflowBelowFields() {
- return cflowBelowFields;
- }
-
- public Map<String, Object> getCflowFields() {
- return cflowFields;
- }
-
- public void clearCaches() {
- cflowFields.clear();
- cflowBelowFields.clear();
- }
-
- }
|